Skip to content

Commit 56fb29f

Browse files
authored
Merge pull request #268 from dhardy/mock
StepRng
2 parents 95b15f8 + ca91a19 commit 56fb29f

File tree

5 files changed

+94
-106
lines changed

5 files changed

+94
-106
lines changed

src/distributions/float.rs

Lines changed: 11 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -98,73 +98,58 @@ float_impls! { f32_rand_impls, f32, 23, next_f32 }
9898

9999
#[cfg(test)]
100100
mod tests {
101-
use {Rng, RngCore, impls};
101+
use Rng;
102+
use mock::StepRng;
102103
use distributions::{Open01, Closed01};
103104

104105
const EPSILON32: f32 = ::core::f32::EPSILON;
105106
const EPSILON64: f64 = ::core::f64::EPSILON;
106107

107-
struct ConstantRng(u64);
108-
impl RngCore for ConstantRng {
109-
fn next_u32(&mut self) -> u32 {
110-
let ConstantRng(v) = *self;
111-
v as u32
112-
}
113-
fn next_u64(&mut self) -> u64 {
114-
let ConstantRng(v) = *self;
115-
v
116-
}
117-
118-
fn fill_bytes(&mut self, dest: &mut [u8]) {
119-
impls::fill_bytes_via_u64(self, dest)
120-
}
121-
}
122-
123108
#[test]
124109
fn floating_point_edge_cases() {
125-
let mut zeros = ConstantRng(0);
110+
let mut zeros = StepRng::new(0, 0);
126111
assert_eq!(zeros.gen::<f32>(), 0.0);
127112
assert_eq!(zeros.gen::<f64>(), 0.0);
128113

129-
let mut one = ConstantRng(1);
114+
let mut one = StepRng::new(1, 0);
130115
assert_eq!(one.gen::<f32>(), EPSILON32);
131116
assert_eq!(one.gen::<f64>(), EPSILON64);
132117

133-
let mut max = ConstantRng(!0);
118+
let mut max = StepRng::new(!0, 0);
134119
assert_eq!(max.gen::<f32>(), 1.0 - EPSILON32);
135120
assert_eq!(max.gen::<f64>(), 1.0 - EPSILON64);
136121
}
137122

138123
#[test]
139124
fn fp_closed_edge_cases() {
140-
let mut zeros = ConstantRng(0);
125+
let mut zeros = StepRng::new(0, 0);
141126
assert_eq!(zeros.sample::<f32, _>(Closed01), 0.0);
142127
assert_eq!(zeros.sample::<f64, _>(Closed01), 0.0);
143128

144-
let mut one = ConstantRng(1);
129+
let mut one = StepRng::new(1, 0);
145130
let one32 = one.sample::<f32, _>(Closed01);
146131
let one64 = one.sample::<f64, _>(Closed01);
147132
assert!(EPSILON32 < one32 && one32 < EPSILON32 * 1.01);
148133
assert!(EPSILON64 < one64 && one64 < EPSILON64 * 1.01);
149134

150-
let mut max = ConstantRng(!0);
135+
let mut max = StepRng::new(!0, 0);
151136
assert_eq!(max.sample::<f32, _>(Closed01), 1.0);
152137
assert_eq!(max.sample::<f64, _>(Closed01), 1.0);
153138
}
154139

155140
#[test]
156141
fn fp_open_edge_cases() {
157-
let mut zeros = ConstantRng(0);
142+
let mut zeros = StepRng::new(0, 0);
158143
assert_eq!(zeros.sample::<f32, _>(Open01), 0.0 + EPSILON32 / 2.0);
159144
assert_eq!(zeros.sample::<f64, _>(Open01), 0.0 + EPSILON64 / 2.0);
160145

161-
let mut one = ConstantRng(1);
146+
let mut one = StepRng::new(1, 0);
162147
let one32 = one.sample::<f32, _>(Open01);
163148
let one64 = one.sample::<f64, _>(Open01);
164149
assert!(EPSILON32 < one32 && one32 < EPSILON32 * 2.0);
165150
assert!(EPSILON64 < one64 && one64 < EPSILON64 * 2.0);
166151

167-
let mut max = ConstantRng(!0);
152+
let mut max = StepRng::new(!0, 0);
168153
assert_eq!(max.sample::<f32, _>(Open01), 1.0 - EPSILON32 / 2.0);
169154
assert_eq!(max.sample::<f64, _>(Open01), 1.0 - EPSILON64 / 2.0);
170155
}

src/distributions/mod.rs

Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -386,26 +386,10 @@ fn ziggurat<R: Rng + ?Sized, P, Z>(
386386

387387
#[cfg(test)]
388388
mod tests {
389-
use {Rng, RngCore};
390-
use impls;
389+
use Rng;
390+
use mock::StepRng;
391391
use super::{WeightedChoice, Weighted, Distribution};
392392

393-
// 0, 1, 2, 3, ...
394-
struct CountingRng { i: u32 }
395-
impl RngCore for CountingRng {
396-
fn next_u32(&mut self) -> u32 {
397-
self.i += 1;
398-
self.i - 1
399-
}
400-
fn next_u64(&mut self) -> u64 {
401-
self.next_u32() as u64
402-
}
403-
404-
fn fill_bytes(&mut self, dest: &mut [u8]) {
405-
impls::fill_bytes_via_u32(self, dest)
406-
}
407-
}
408-
409393
#[test]
410394
fn test_weighted_choice() {
411395
// this makes assumptions about the internal implementation of
@@ -419,7 +403,7 @@ mod tests {
419403
let wc = WeightedChoice::new(&mut items);
420404
let expected = $expected;
421405

422-
let mut rng = CountingRng { i: 0 };
406+
let mut rng = StepRng::new(0, 1);
423407

424408
for &val in expected.iter() {
425409
assert_eq!(wc.sample(&mut rng), val)

src/lib.rs

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,7 @@ use distributions::range::SampleRange;
297297
pub mod distributions;
298298
mod impls;
299299
pub mod jitter;
300+
pub mod mock;
300301
#[cfg(feature="std")] pub mod os;
301302
#[cfg(feature="std")] pub mod read;
302303
pub mod reseeding;
@@ -1380,7 +1381,7 @@ pub fn sample<T, I, R>(rng: &mut R, iterable: I, amount: usize) -> Vec<T>
13801381

13811382
#[cfg(test)]
13821383
mod test {
1383-
use impls;
1384+
use mock::StepRng;
13841385
#[cfg(feature="std")]
13851386
use super::{random, thread_rng, EntropyRng};
13861387
use super::{RngCore, Rng, SeedableRng, StdRng};
@@ -1419,16 +1420,6 @@ mod test {
14191420
TestRng { inner: StdRng::from_seed(seed) }
14201421
}
14211422

1422-
struct ConstRng { i: u64 }
1423-
impl RngCore for ConstRng {
1424-
fn next_u32(&mut self) -> u32 { self.i as u32 }
1425-
fn next_u64(&mut self) -> u64 { self.i }
1426-
1427-
fn fill_bytes(&mut self, dest: &mut [u8]) {
1428-
impls::fill_bytes_via_u64(self, dest)
1429-
}
1430-
}
1431-
14321423
#[test]
14331424
#[cfg(feature="std")]
14341425
fn test_entropy() {
@@ -1438,7 +1429,7 @@ mod test {
14381429

14391430
#[test]
14401431
fn test_fill_bytes_default() {
1441-
let mut r = ConstRng { i: 0x11_22_33_44_55_66_77_88 };
1432+
let mut r = StepRng::new(0x11_22_33_44_55_66_77_88, 0);
14421433

14431434
// check every remainder mod 8, both in small and big vectors.
14441435
let lengths = [0, 1, 2, 3, 4, 5, 6, 7,
@@ -1460,7 +1451,7 @@ mod test {
14601451
#[test]
14611452
fn test_fill() {
14621453
let x = 9041086907909331047; // a random u64
1463-
let mut rng = ConstRng { i: x };
1454+
let mut rng = StepRng::new(x, 0);
14641455

14651456
// Convert to byte sequence and back to u64; byte-swap twice if BE.
14661457
let mut array = [0u64; 2];

src/mock.rs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// https://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
//! Mock random number generator
12+
13+
use {RngCore, Error, impls};
14+
15+
/// A simple implementation of `RngCore` for testing purposes.
16+
///
17+
/// This generates an arithmetic sequence (i.e. adds a constant each step)
18+
/// over a `u64` number, using wrapping arithmetic. If the increment is 0
19+
/// the generator yields a constant.
20+
///
21+
/// ```rust
22+
/// use rand::Rng;
23+
/// use rand::mock::StepRng;
24+
///
25+
/// let mut my_rng = StepRng::new(2, 1);
26+
/// let sample: [u64; 3] = my_rng.gen();
27+
/// assert_eq!(sample, [2, 3, 4]);
28+
/// ```
29+
#[derive(Debug, Clone)]
30+
pub struct StepRng {
31+
v: u64,
32+
a: u64,
33+
}
34+
35+
impl StepRng {
36+
/// Create a `StepRng`, yielding an arithmetic sequence starting with
37+
/// `initial` and incremented by `increment` each time.
38+
pub fn new(initial: u64, increment: u64) -> Self {
39+
StepRng { v: initial, a: increment }
40+
}
41+
}
42+
43+
impl RngCore for StepRng {
44+
fn next_u32(&mut self) -> u32 {
45+
self.next_u64() as u32
46+
}
47+
48+
fn next_u64(&mut self) -> u64 {
49+
let result = self.v;
50+
self.v = self.v.wrapping_add(self.a);
51+
result
52+
}
53+
54+
fn fill_bytes(&mut self, dest: &mut [u8]) {
55+
impls::fill_bytes_via_u64(self, dest);
56+
}
57+
58+
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
59+
Ok(self.fill_bytes(dest))
60+
}
61+
}

src/reseeding.rs

Lines changed: 15 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -182,57 +182,24 @@ impl<R: RngCore + SeedableRng, Rsdr: RngCore> RngCore for ReseedingRng<R, Rsdr>
182182

183183
#[cfg(test)]
184184
mod test {
185-
use {impls, le};
186-
use super::{ReseedingRng};
187-
use {SeedableRng, RngCore, Error};
188-
189-
struct Counter {
190-
i: u32
191-
}
192-
193-
impl RngCore for Counter {
194-
fn next_u32(&mut self) -> u32 {
195-
self.i += 1;
196-
// very random
197-
self.i - 1
198-
}
199-
fn next_u64(&mut self) -> u64 {
200-
impls::next_u64_via_u32(self)
201-
}
202-
203-
fn fill_bytes(&mut self, dest: &mut [u8]) {
204-
impls::fill_bytes_via_u64(self, dest)
205-
}
206-
}
207-
impl SeedableRng for Counter {
208-
type Seed = [u8; 4];
209-
fn from_seed(seed: Self::Seed) -> Self {
210-
let mut seed_u32 = [0u32; 1];
211-
le::read_u32_into(&seed, &mut seed_u32);
212-
Counter { i: seed_u32[0] }
213-
}
214-
}
215-
216-
#[derive(Debug, Clone)]
217-
struct ResetCounter;
218-
impl RngCore for ResetCounter {
219-
fn next_u32(&mut self) -> u32 { unimplemented!() }
220-
fn next_u64(&mut self) -> u64 { unimplemented!() }
221-
fn fill_bytes(&mut self, _dest: &mut [u8]) { unimplemented!() }
222-
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
223-
for i in dest.iter_mut() { *i = 0; }
224-
Ok(())
225-
}
226-
}
185+
use {Rng, SeedableRng, StdRng};
186+
use mock::StepRng;
187+
use super::ReseedingRng;
227188

228189
#[test]
229190
fn test_reseeding() {
230-
let mut rs = ReseedingRng::new(Counter {i:0}, 400, ResetCounter);
231-
232-
let mut i = 0;
233-
for _ in 0..1000 {
234-
assert_eq!(rs.next_u32(), i % 100);
235-
i += 1;
191+
let mut zero = StepRng::new(0, 0);
192+
let rng = StdRng::from_rng(&mut zero).unwrap();
193+
let mut reseeding = ReseedingRng::new(rng, 32, zero);
194+
195+
// Currently we only support for arrays up to length 32.
196+
// TODO: cannot generate seq via Rng::gen because it uses different alg
197+
let mut buf = [0u8; 32];
198+
reseeding.fill(&mut buf);
199+
let seq = buf;
200+
for _ in 0..10 {
201+
reseeding.fill(&mut buf);
202+
assert_eq!(buf, seq);
236203
}
237204
}
238205
}

0 commit comments

Comments
 (0)