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