]> git.lizzy.rs Git - rust.git/blob - src/librand/reseeding.rs
core: Fix size_hint for signed integer Range<T> iterators
[rust.git] / src / librand / reseeding.rs
1 // Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://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 //! A wrapper around another RNG that reseeds it after it
12 //! generates a certain number of random bytes.
13
14 use core::prelude::*;
15
16 use {Rng, SeedableRng};
17
18 /// How many bytes of entropy the underling RNG is allowed to generate
19 /// before it is reseeded.
20 const DEFAULT_GENERATION_THRESHOLD: usize = 32 * 1024;
21
22 /// A wrapper around any RNG which reseeds the underlying RNG after it
23 /// has generated a certain number of random bytes.
24 pub struct ReseedingRng<R, Rsdr> {
25     rng: R,
26     generation_threshold: usize,
27     bytes_generated: usize,
28     /// Controls the behaviour when reseeding the RNG.
29     pub reseeder: Rsdr,
30 }
31
32 impl<R: Rng, Rsdr: Reseeder<R>> ReseedingRng<R, Rsdr> {
33     /// Create a new `ReseedingRng` with the given parameters.
34     ///
35     /// # Arguments
36     ///
37     /// * `rng`: the random number generator to use.
38     /// * `generation_threshold`: the number of bytes of entropy at which to reseed the RNG.
39     /// * `reseeder`: the reseeding object to use.
40     pub fn new(rng: R, generation_threshold: usize, reseeder: Rsdr) -> ReseedingRng<R,Rsdr> {
41         ReseedingRng {
42             rng: rng,
43             generation_threshold: generation_threshold,
44             bytes_generated: 0,
45             reseeder: reseeder
46         }
47     }
48
49     /// Reseed the internal RNG if the number of bytes that have been
50     /// generated exceed the threshold.
51     pub fn reseed_if_necessary(&mut self) {
52         if self.bytes_generated >= self.generation_threshold {
53             self.reseeder.reseed(&mut self.rng);
54             self.bytes_generated = 0;
55         }
56     }
57 }
58
59
60 impl<R: Rng, Rsdr: Reseeder<R>> Rng for ReseedingRng<R, Rsdr> {
61     fn next_u32(&mut self) -> u32 {
62         self.reseed_if_necessary();
63         self.bytes_generated += 4;
64         self.rng.next_u32()
65     }
66
67     fn next_u64(&mut self) -> u64 {
68         self.reseed_if_necessary();
69         self.bytes_generated += 8;
70         self.rng.next_u64()
71     }
72
73     fn fill_bytes(&mut self, dest: &mut [u8]) {
74         self.reseed_if_necessary();
75         self.bytes_generated += dest.len();
76         self.rng.fill_bytes(dest)
77     }
78 }
79
80 impl<S, R: SeedableRng<S>, Rsdr: Reseeder<R> + Default>
81      SeedableRng<(Rsdr, S)> for ReseedingRng<R, Rsdr> {
82     fn reseed(&mut self, (rsdr, seed): (Rsdr, S)) {
83         self.rng.reseed(seed);
84         self.reseeder = rsdr;
85         self.bytes_generated = 0;
86     }
87
88     /// Create a new `ReseedingRng` from the given reseeder and
89     /// seed. This uses a default value for `generation_threshold`.
90     fn from_seed((rsdr, seed): (Rsdr, S)) -> ReseedingRng<R, Rsdr> {
91         ReseedingRng {
92             rng: SeedableRng::from_seed(seed),
93             generation_threshold: DEFAULT_GENERATION_THRESHOLD,
94             bytes_generated: 0,
95             reseeder: rsdr
96         }
97     }
98 }
99
100 /// Something that can be used to reseed an RNG via `ReseedingRng`.
101 pub trait Reseeder<R> {
102     /// Reseed the given RNG.
103     fn reseed(&mut self, rng: &mut R);
104 }
105
106 /// Reseed an RNG using a `Default` instance. This reseeds by
107 /// replacing the RNG with the result of a `Default::default` call.
108 #[derive(Copy, Clone)]
109 pub struct ReseedWithDefault;
110
111 impl<R: Rng + Default> Reseeder<R> for ReseedWithDefault {
112     fn reseed(&mut self, rng: &mut R) {
113         *rng = Default::default();
114     }
115 }
116 #[stable(feature = "rust1", since = "1.0.0")]
117 impl Default for ReseedWithDefault {
118     #[stable(feature = "rust1", since = "1.0.0")]
119     fn default() -> ReseedWithDefault { ReseedWithDefault }
120 }
121
122 #[cfg(test)]
123 mod test {
124     use std::prelude::v1::*;
125
126     use core::iter::{order, repeat};
127     use super::{ReseedingRng, ReseedWithDefault};
128     use {SeedableRng, Rng};
129
130     struct Counter {
131         i: u32
132     }
133
134     impl Rng for Counter {
135         fn next_u32(&mut self) -> u32 {
136             self.i += 1;
137             // very random
138             self.i - 1
139         }
140     }
141     impl Default for Counter {
142         fn default() -> Counter {
143             Counter { i: 0 }
144         }
145     }
146     impl SeedableRng<u32> for Counter {
147         fn reseed(&mut self, seed: u32) {
148             self.i = seed;
149         }
150         fn from_seed(seed: u32) -> Counter {
151             Counter { i: seed }
152         }
153     }
154     type MyRng = ReseedingRng<Counter, ReseedWithDefault>;
155
156     #[test]
157     fn test_reseeding() {
158         let mut rs = ReseedingRng::new(Counter {i:0}, 400, ReseedWithDefault);
159
160         let mut i = 0;
161         for _ in 0..1000 {
162             assert_eq!(rs.next_u32(), i % 100);
163             i += 1;
164         }
165     }
166
167     #[test]
168     fn test_rng_seeded() {
169         let mut ra: MyRng = SeedableRng::from_seed((ReseedWithDefault, 2));
170         let mut rb: MyRng = SeedableRng::from_seed((ReseedWithDefault, 2));
171         assert!(order::equals(ra.gen_ascii_chars().take(100),
172                               rb.gen_ascii_chars().take(100)));
173     }
174
175     #[test]
176     fn test_rng_reseed() {
177         let mut r: MyRng = SeedableRng::from_seed((ReseedWithDefault, 3));
178         let string1: String = r.gen_ascii_chars().take(100).collect();
179
180         r.reseed((ReseedWithDefault, 3));
181
182         let string2: String = r.gen_ascii_chars().take(100).collect();
183         assert_eq!(string1, string2);
184     }
185
186     const FILL_BYTES_V_LEN: usize = 13579;
187     #[test]
188     fn test_rng_fill_bytes() {
189         let mut v = repeat(0).take(FILL_BYTES_V_LEN).collect::<Vec<_>>();
190         ::test::rng().fill_bytes(&mut v);
191
192         // Sanity test: if we've gotten here, `fill_bytes` has not infinitely
193         // recursed.
194         assert_eq!(v.len(), FILL_BYTES_V_LEN);
195
196         // To test that `fill_bytes` actually did something, check that the
197         // average of `v` is not 0.
198         let mut sum = 0.0;
199         for &x in &v {
200             sum += x as f64;
201         }
202         assert!(sum / v.len() as f64 != 0.0);
203     }
204 }