Skip to content

Commit 08924a3

Browse files
committed
Remove Result from BlockRngCore::generate
1 parent 963be0c commit 08924a3

File tree

5 files changed

+32
-73
lines changed

5 files changed

+32
-73
lines changed

rand-core/src/impls.rs

Lines changed: 12 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -177,11 +177,6 @@ pub fn next_u64_via_fill<R: RngCore + ?Sized>(rng: &mut R) -> u64 {
177177
/// implementation to write the results directly to the destination slice.
178178
/// No generated values are ever thown away.
179179
///
180-
/// Although `BlockCoreRng::generate` can return a `Result`, we assume all PRNGs
181-
/// to be infallible, and for the `Result` to only have a signaling function.
182-
/// Therefore, the error is only reported by `try_fill_bytes`, all other
183-
/// functions squelch the error.
184-
///
185180
/// For easy initialization `BlockRng` also implements [`SeedableRng`].
186181
///
187182
/// [`BlockRngCore`]: ../BlockRngCore.t.html
@@ -209,7 +204,7 @@ impl<R: BlockRngCore<u32>> RngCore for BlockRng<R> {
209204
#[inline(always)]
210205
fn next_u32(&mut self) -> u32 {
211206
if self.index >= self.results.as_ref().len() {
212-
let _ = self.core.generate(&mut self.results);
207+
self.core.generate(&mut self.results);
213208
self.index = 0;
214209
}
215210

@@ -239,29 +234,24 @@ impl<R: BlockRngCore<u32>> RngCore for BlockRng<R> {
239234
// Read an u64 from the current index
240235
read_u64(self.results.as_ref(), index)
241236
} else if index >= len {
242-
let _ = self.core.generate(&mut self.results);
237+
self.core.generate(&mut self.results);
243238
self.index = 2;
244239
read_u64(self.results.as_ref(), 0)
245240
} else {
246241
let x = self.results.as_ref()[len-1] as u64;
247-
let _ = self.core.generate(&mut self.results);
242+
self.core.generate(&mut self.results);
248243
self.index = 1;
249244
let y = self.results.as_ref()[0] as u64;
250245
(y << 32) | x
251246
}
252247
}
253248

254-
fn fill_bytes(&mut self, dest: &mut [u8]) {
255-
let _ = self.try_fill_bytes(dest);
256-
}
257-
258249
// As an optimization we try to write directly into the output buffer.
259250
// This is only enabled for little-endian platforms where unaligned writes
260251
// are known to be safe and fast.
261252
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
262-
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
253+
fn fill_bytes(&mut self, dest: &mut [u8]) {
263254
let mut filled = 0;
264-
let mut res = Ok(());
265255

266256
// Continue filling from the current set of results
267257
if self.index < self.results.as_ref().len() {
@@ -281,33 +271,27 @@ impl<R: BlockRngCore<u32>> RngCore for BlockRng<R> {
281271
let dest_u32: &mut R::Results = unsafe {
282272
::core::mem::transmute(dest[filled..].as_mut_ptr())
283273
};
284-
let res2 = self.core.generate(dest_u32);
285-
if res2.is_err() && res.is_ok() { res = res2 };
274+
self.core.generate(dest_u32);
286275
filled += self.results.as_ref().len() * 4;
287276
}
288277
self.index = self.results.as_ref().len();
289278

290279
if len_remainder > 0 {
291-
let res2 = self.core.generate(&mut self.results);
292-
if res2.is_err() && res.is_ok() { res = res2 };
293-
280+
self.core.generate(&mut self.results);
294281
let (consumed_u32, _) =
295282
fill_via_u32_chunks(&mut self.results.as_ref(),
296283
&mut dest[filled..]);
297284

298285
self.index = consumed_u32;
299286
}
300-
res
301287
}
302288

303289
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
304-
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
305-
let mut res = Ok(());
290+
fn fill_bytes(&mut self, dest: &mut [u8]) {
306291
let mut read_len = 0;
307292
while read_len < dest.len() {
308293
if self.index >= self.results.as_ref().len() {
309-
let res2 = self.core.generate(&mut self.results);
310-
if res2.is_err() && res.is_ok() { res = res2 };
294+
self.core.generate(&mut self.results);
311295
self.index = 0;
312296
}
313297
let (consumed_u32, filled_u8) =
@@ -317,7 +301,10 @@ impl<R: BlockRngCore<u32>> RngCore for BlockRng<R> {
317301
self.index += consumed_u32;
318302
read_len += filled_u8;
319303
}
320-
res
304+
}
305+
306+
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
307+
Ok(self.fill_bytes(dest))
321308
}
322309
}
323310

rand-core/src/lib.rs

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -171,16 +171,7 @@ pub trait BlockRngCore<T>: Sized {
171171
type Results: AsRef<[T]> + Default;
172172

173173
/// Generate a new block of results.
174-
///
175-
/// The result type is unnecessary for PRNGs, which we assume to be
176-
/// infallible. It only has a signalling function, for example to report a
177-
/// failed reseed, that the PRNG is used beyond its limits, or because it
178-
/// 'noticed' some kind of interference (like fork protection).
179-
///
180-
/// In all cases user code is allowed to ignore any errors from `generate`
181-
/// and to expect the generator to keep working, even though it may not be
182-
/// in the most ideal conditions.
183-
fn generate(&mut self, results: &mut Self::Results) -> Result<(), Error>;
174+
fn generate(&mut self, results: &mut Self::Results);
184175
}
185176

186177
/// A marker trait for an `Rng` which may be considered for use in

src/prng/chacha.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ macro_rules! double_round{
222222
impl BlockRngCore<u32> for ChaChaCore {
223223
type Results = [u32; STATE_WORDS];
224224

225-
fn generate(&mut self, results: &mut Self::Results) -> Result<(), Error> {
225+
fn generate(&mut self, results: &mut Self::Results) {
226226
// For some reason extracting this part into a separate function
227227
// improves performance by 50%.
228228
fn core(results: &mut [u32; STATE_WORDS],
@@ -242,13 +242,12 @@ impl BlockRngCore<u32> for ChaChaCore {
242242

243243
// update 128-bit counter
244244
self.state[12] = self.state[12].wrapping_add(1);
245-
if self.state[12] != 0 { return Ok(()) };
245+
if self.state[12] != 0 { return; };
246246
self.state[13] = self.state[13].wrapping_add(1);
247-
if self.state[13] != 0 { return Ok(()) };
247+
if self.state[13] != 0 { return; };
248248
self.state[14] = self.state[14].wrapping_add(1);
249-
if self.state[14] != 0 { return Ok(()) };
249+
if self.state[14] != 0 { return; };
250250
self.state[15] = self.state[15].wrapping_add(1);
251-
Ok(())
252251
}
253252
}
254253

src/prng/hc128.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ impl fmt::Debug for Hc128Core {
114114
impl BlockRngCore<u32> for Hc128Core {
115115
type Results = [u32; 16];
116116

117-
fn generate(&mut self, results: &mut Self::Results) -> Result<(), Error> {
117+
fn generate(&mut self, results: &mut Self::Results) {
118118
assert!(self.counter1024 % 16 == 0);
119119

120120
let cc = self.counter1024 % 512;
@@ -159,7 +159,6 @@ impl BlockRngCore<u32> for Hc128Core {
159159
results[15] = self.step_q(cc+15, dd+0, cc+12, cc+5, cc+3);
160160
}
161161
self.counter1024 = self.counter1024.wrapping_add(16);
162-
Ok(())
163162
}
164163
}
165164

src/reseeding.rs

Lines changed: 14 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -45,17 +45,11 @@ use rand_core::impls::BlockRng;
4545
///
4646
/// # Error handling
4747
///
48-
/// It is usually best to use the infallible methods `next_u32`, `next_u64` and
49-
/// `fill_bytes`, because `ReseedingRng` and the wrapped PRNG always continue
50-
/// working, they never need error handling. Only use `try_fill_bytes` if you
51-
/// care to (and are prepared to) handle errors due to a failed reseed.
52-
///
53-
/// If reseeding fails, `try_fill_bytes` is the only `Rng` method to report it.
54-
/// For all other `Rng` methods, `ReseedingRng` will not panic but try to
55-
/// handle the error intelligently through some combination of retrying and
56-
/// delaying reseeding until later. If handling the source error fails these
57-
/// methods will continue generating data from the wrapped PRNG without
58-
/// reseeding.
48+
/// Although extremely unlikely, reseeding the wrapped PRNG can fail.
49+
/// `ReseedingRng` will never panic but try to handle the error intelligently
50+
/// through some combination of retrying and delaying reseeding until later.
51+
/// If handling the source error fails `ReseedingRng` will continue generating
52+
/// data from the wrapped PRNG without reseeding.
5953
#[derive(Debug)]
6054
pub struct ReseedingRng<R, Rsdr>(BlockRng<ReseedingCore<R, Rsdr>>)
6155
where R: BlockRngCore<u32> + SeedableRng,
@@ -135,19 +129,15 @@ where R: BlockRngCore<u32> + SeedableRng,
135129
{
136130
type Results = <R as BlockRngCore<u32>>::Results;
137131

138-
fn generate(&mut self, results: &mut Self::Results) -> Result<(), Error> {
132+
fn generate(&mut self, results: &mut Self::Results) {
139133
if self.bytes_until_reseed <= 0 {
140-
// We want to reseed here, and generate results later in the
141-
// function. If generating results fail, we should return the error
142-
// from that. If generating results succeeded, but reseeding failed,
143-
// we should return the error from reseeding.
144-
// The only way to get this behaviour without destroying performance
145-
// was to split part of the function out into a
146-
// `reseed_and_generate` method.
134+
// We get better performance by not calling only `auto_reseed` here
135+
// and continuing with the rest of the function, but by directly
136+
// returning from a non-inlined function.
147137
return self.reseed_and_generate(results);
148138
}
149139
self.bytes_until_reseed -= results.as_ref().len() as i64 * 4;
150-
self.inner.generate(results)
140+
self.inner.generate(results);
151141
}
152142
}
153143

@@ -167,12 +157,10 @@ where R: BlockRngCore<u32> + SeedableRng,
167157
///
168158
/// If reseeding fails, this will try to work around errors intelligently
169159
/// by adjusting the delay until automatic reseeding next occurs.
170-
/// It will still report the error but with kind changed to
171-
/// `ErrorKind::Transient`.
172-
fn auto_reseed(&mut self) -> Result<(), Error> {
160+
fn auto_reseed(&mut self) {
173161
trace!("Reseeding RNG after {} generated bytes",
174162
self.threshold - self.bytes_until_reseed);
175-
if let Err(mut e) = self.reseed() {
163+
if let Err(e) = self.reseed() {
176164
let delay = match e.kind {
177165
ErrorKind::Transient => 0,
178166
kind @ _ if kind.should_retry() => self.threshold >> 8,
@@ -181,23 +169,18 @@ where R: BlockRngCore<u32> + SeedableRng,
181169
warn!("Reseeding RNG delayed reseeding by {} bytes due to \
182170
error from source: {}", delay, e);
183171
self.bytes_until_reseed = delay;
184-
e.kind = ErrorKind::Transient;
185-
Err(e)
186172
} else {
187173
self.bytes_until_reseed = self.threshold;
188-
Ok(())
189174
}
190175
}
191176

192177
#[inline(never)]
193178
fn reseed_and_generate(&mut self,
194179
results: &mut <Self as BlockRngCore<u32>>::Results)
195-
-> Result<(), Error>
196180
{
197-
let res1 = self.auto_reseed();
181+
self.auto_reseed();
198182
self.bytes_until_reseed -= results.as_ref().len() as i64 * 4;
199-
let res2 = self.inner.generate(results);
200-
if res2.is_err() { res2 } else { res1 }
183+
self.inner.generate(results);
201184
}
202185
}
203186

0 commit comments

Comments
 (0)