]> git.lizzy.rs Git - rust.git/blob - src/librand/reseeding.rs
Merge pull request #20510 from tshepang/patch-6
[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 use core::default::Default;
18
19 /// How many bytes of entropy the underling RNG is allowed to generate
20 /// before it is reseeded.
21 static DEFAULT_GENERATION_THRESHOLD: uint = 32 * 1024;
22
23 /// A wrapper around any RNG which reseeds the underlying RNG after it
24 /// has generated a certain number of random bytes.
25 pub struct ReseedingRng<R, Rsdr> {
26     rng: R,
27     generation_threshold: uint,
28     bytes_generated: uint,
29     /// Controls the behaviour when reseeding the RNG.
30     pub reseeder: Rsdr,
31 }
32
33 impl<R: Rng, Rsdr: Reseeder<R>> ReseedingRng<R, Rsdr> {
34     /// Create a new `ReseedingRng` with the given parameters.
35     ///
36     /// # Arguments
37     ///
38     /// * `rng`: the random number generator to use.
39     /// * `generation_threshold`: the number of bytes of entropy at which to reseed the RNG.
40     /// * `reseeder`: the reseeding object to use.
41     pub fn new(rng: R, generation_threshold: uint, reseeder: Rsdr) -> ReseedingRng<R,Rsdr> {
42         ReseedingRng {
43             rng: rng,
44             generation_threshold: generation_threshold,
45             bytes_generated: 0,
46             reseeder: reseeder
47         }
48     }
49
50     /// Reseed the internal RNG if the number of bytes that have been
51     /// generated exceed the threshold.
52     pub fn reseed_if_necessary(&mut self) {
53         if self.bytes_generated >= self.generation_threshold {
54             self.reseeder.reseed(&mut self.rng);
55             self.bytes_generated = 0;
56         }
57     }
58 }
59
60
61 impl<R: Rng, Rsdr: Reseeder<R>> Rng for ReseedingRng<R, Rsdr> {
62     fn next_u32(&mut self) -> u32 {
63         self.reseed_if_necessary();
64         self.bytes_generated += 4;
65         self.rng.next_u32()
66     }
67
68     fn next_u64(&mut self) -> u64 {
69         self.reseed_if_necessary();
70         self.bytes_generated += 8;
71         self.rng.next_u64()
72     }
73
74     fn fill_bytes(&mut self, dest: &mut [u8]) {
75         self.reseed_if_necessary();
76         self.bytes_generated += dest.len();
77         self.rng.fill_bytes(dest)
78     }
79 }
80
81 impl<S, R: SeedableRng<S>, Rsdr: Reseeder<R> + Default>
82      SeedableRng<(Rsdr, S)> for ReseedingRng<R, Rsdr> {
83     fn reseed(&mut self, (rsdr, seed): (Rsdr, S)) {
84         self.rng.reseed(seed);
85         self.reseeder = rsdr;
86         self.bytes_generated = 0;
87     }
88
89     /// Create a new `ReseedingRng` from the given reseeder and
90     /// seed. This uses a default value for `generation_threshold`.
91     fn from_seed((rsdr, seed): (Rsdr, S)) -> ReseedingRng<R, Rsdr> {
92         ReseedingRng {
93             rng: SeedableRng::from_seed(seed),
94             generation_threshold: DEFAULT_GENERATION_THRESHOLD,
95             bytes_generated: 0,
96             reseeder: rsdr
97         }
98     }
99 }
100
101 /// Something that can be used to reseed an RNG via `ReseedingRng`.
102 ///
103 /// # Example
104 ///
105 /// ```rust
106 /// use std::rand::{Rng, SeedableRng, StdRng};
107 /// use std::rand::reseeding::{Reseeder, ReseedingRng};
108 ///
109 /// struct TickTockReseeder { tick: bool }
110 /// impl Reseeder<StdRng> for TickTockReseeder {
111 ///     fn reseed(&mut self, rng: &mut StdRng) {
112 ///         let val = if self.tick {0} else {1};
113 ///         rng.reseed(&[val]);
114 ///         self.tick = !self.tick;
115 ///     }
116 /// }
117 /// fn main() {
118 ///     let rsdr = TickTockReseeder { tick: true };
119 ///
120 ///     let inner = StdRng::new().unwrap();
121 ///     let mut rng = ReseedingRng::new(inner, 10, rsdr);
122 ///
123 ///     // this will repeat, because it gets reseeded very regularly.
124 ///     let s: String = rng.gen_ascii_chars().take(100).collect();
125 ///     println!("{}", s);
126 /// }
127 ///
128 /// ```
129 pub trait Reseeder<R> {
130     /// Reseed the given RNG.
131     fn reseed(&mut self, rng: &mut R);
132 }
133
134 /// Reseed an RNG using a `Default` instance. This reseeds by
135 /// replacing the RNG with the result of a `Default::default` call.
136 #[derive(Copy)]
137 pub struct ReseedWithDefault;
138
139 impl<R: Rng + Default> Reseeder<R> for ReseedWithDefault {
140     fn reseed(&mut self, rng: &mut R) {
141         *rng = Default::default();
142     }
143 }
144 #[stable]
145 impl Default for ReseedWithDefault {
146     #[stable]
147     fn default() -> ReseedWithDefault { ReseedWithDefault }
148 }
149
150 #[cfg(test)]
151 mod test {
152     use std::prelude::v1::*;
153
154     use core::iter::{order, repeat};
155     use super::{ReseedingRng, ReseedWithDefault};
156     use std::default::Default;
157     use {SeedableRng, Rng};
158
159     struct Counter {
160         i: u32
161     }
162
163     impl Rng for Counter {
164         fn next_u32(&mut self) -> u32 {
165             self.i += 1;
166             // very random
167             self.i - 1
168         }
169     }
170     impl Default for Counter {
171         fn default() -> Counter {
172             Counter { i: 0 }
173         }
174     }
175     impl SeedableRng<u32> for Counter {
176         fn reseed(&mut self, seed: u32) {
177             self.i = seed;
178         }
179         fn from_seed(seed: u32) -> Counter {
180             Counter { i: seed }
181         }
182     }
183     type MyRng = ReseedingRng<Counter, ReseedWithDefault>;
184
185     #[test]
186     fn test_reseeding() {
187         let mut rs = ReseedingRng::new(Counter {i:0}, 400, ReseedWithDefault);
188
189         let mut i = 0;
190         for _ in range(0u, 1000) {
191             assert_eq!(rs.next_u32(), i % 100);
192             i += 1;
193         }
194     }
195
196     #[test]
197     fn test_rng_seeded() {
198         let mut ra: MyRng = SeedableRng::from_seed((ReseedWithDefault, 2));
199         let mut rb: MyRng = SeedableRng::from_seed((ReseedWithDefault, 2));
200         assert!(order::equals(ra.gen_ascii_chars().take(100),
201                               rb.gen_ascii_chars().take(100)));
202     }
203
204     #[test]
205     fn test_rng_reseed() {
206         let mut r: MyRng = SeedableRng::from_seed((ReseedWithDefault, 3));
207         let string1: String = r.gen_ascii_chars().take(100).collect();
208
209         r.reseed((ReseedWithDefault, 3));
210
211         let string2: String = r.gen_ascii_chars().take(100).collect();
212         assert_eq!(string1, string2);
213     }
214
215     static FILL_BYTES_V_LEN: uint = 13579;
216     #[test]
217     fn test_rng_fill_bytes() {
218         let mut v = repeat(0u8).take(FILL_BYTES_V_LEN).collect::<Vec<_>>();
219         ::test::rng().fill_bytes(v.as_mut_slice());
220
221         // Sanity test: if we've gotten here, `fill_bytes` has not infinitely
222         // recursed.
223         assert_eq!(v.len(), FILL_BYTES_V_LEN);
224
225         // To test that `fill_bytes` actually did something, check that the
226         // average of `v` is not 0.
227         let mut sum = 0.0;
228         for &x in v.iter() {
229             sum += x as f64;
230         }
231         assert!(sum / v.len() as f64 != 0.0);
232     }
233 }