(index<- ) ./librand/reseeding.rs
git branch: * master 5200215 auto merge of #14035 : alexcrichton/rust/experimental, r=huonw
modified: Wed Apr 9 17:27:02 2014
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 std::default::Default;
15 use {Rng, SeedableRng};
16
17 /// How many bytes of entropy the underling RNG is allowed to generate
18 /// before it is reseeded.
19 static DEFAULT_GENERATION_THRESHOLD: uint = 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: uint,
26 bytes_generated: uint,
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: uint, 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
59 impl<R: Rng, Rsdr: Reseeder<R>> Rng for ReseedingRng<R, Rsdr> {
60 fn next_u32(&mut self) -> u32 {
61 self.reseed_if_necessary();
62 self.bytes_generated += 4;
63 self.rng.next_u32()
64 }
65
66 fn next_u64(&mut self) -> u64 {
67 self.reseed_if_necessary();
68 self.bytes_generated += 8;
69 self.rng.next_u64()
70 }
71
72 fn fill_bytes(&mut self, dest: &mut [u8]) {
73 self.reseed_if_necessary();
74 self.bytes_generated += dest.len();
75 self.rng.fill_bytes(dest)
76 }
77 }
78
79 impl<S, R: SeedableRng<S>, Rsdr: Reseeder<R>>
80 SeedableRng<(Rsdr, S)> for ReseedingRng<R, Rsdr> {
81 fn reseed(&mut self, (rsdr, seed): (Rsdr, S)) {
82 self.rng.reseed(seed);
83 self.reseeder = rsdr;
84 self.bytes_generated = 0;
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 /// Something that can be used to reseed an RNG via `ReseedingRng`.
99 ///
100 /// # Example
101 ///
102 /// ```rust
103 /// use rand::{Rng, SeedableRng, StdRng};
104 /// use rand::reseeding::{Reseeder, ReseedingRng};
105 ///
106 /// struct TickTockReseeder { tick: bool }
107 /// impl Reseeder<StdRng> for TickTockReseeder {
108 /// fn reseed(&mut self, rng: &mut StdRng) {
109 /// let val = if self.tick {0} else {1};
110 /// rng.reseed(&[val]);
111 /// self.tick = !self.tick;
112 /// }
113 /// }
114 /// fn main() {
115 /// let rsdr = TickTockReseeder { tick: true };
116 ///
117 /// let inner = StdRng::new().unwrap();
118 /// let mut rng = ReseedingRng::new(inner, 10, rsdr);
119 ///
120 /// // this will repeat, because it gets reseeded very regularly.
121 /// println!("{}", rng.gen_ascii_str(100));
122 /// }
123 ///
124 /// ```
125 pub trait Reseeder<R> {
126 /// Reseed the given RNG.
127 fn reseed(&mut self, rng: &mut R);
128 }
129
130 /// Reseed an RNG using a `Default` instance. This reseeds by
131 /// replacing the RNG with the result of a `Default::default` call.
132 pub struct ReseedWithDefault;
133
134 impl<R: Rng + Default> Reseeder<R> for ReseedWithDefault {
135 fn reseed(&mut self, rng: &mut R) {
136 *rng = Default::default();
137 }
138 }
139 impl Default for ReseedWithDefault {
140 fn default() -> ReseedWithDefault { ReseedWithDefault }
141 }
142
143 #[cfg(test)]
144 mod test {
145 use super::{ReseedingRng, ReseedWithDefault};
146 use std::default::Default;
147 use {SeedableRng, Rng};
148
149 struct Counter {
150 i: u32
151 }
152
153 impl Rng for Counter {
154 fn next_u32(&mut self) -> u32 {
155 self.i += 1;
156 // very random
157 self.i - 1
158 }
159 }
160 impl Default for Counter {
161 fn default() -> Counter {
162 Counter { i: 0 }
163 }
164 }
165 impl SeedableRng<u32> for Counter {
166 fn reseed(&mut self, seed: u32) {
167 self.i = seed;
168 }
169 fn from_seed(seed: u32) -> Counter {
170 Counter { i: seed }
171 }
172 }
173 type MyRng = ReseedingRng<Counter, ReseedWithDefault>;
174
175 #[test]
176 fn test_reseeding() {
177 let mut rs = ReseedingRng::new(Counter {i:0}, 400, ReseedWithDefault);
178
179 let mut i = 0;
180 for _ in range(0, 1000) {
181 assert_eq!(rs.next_u32(), i % 100);
182 i += 1;
183 }
184 }
185
186 #[test]
187 fn test_rng_seeded() {
188 let mut ra: MyRng = SeedableRng::from_seed((ReseedWithDefault, 2));
189 let mut rb: MyRng = SeedableRng::from_seed((ReseedWithDefault, 2));
190 assert_eq!(ra.gen_ascii_str(100u), rb.gen_ascii_str(100u));
191 }
192
193 #[test]
194 fn test_rng_reseed() {
195 let mut r: MyRng = SeedableRng::from_seed((ReseedWithDefault, 3));
196 let string1 = r.gen_ascii_str(100);
197
198 r.reseed((ReseedWithDefault, 3));
199
200 let string2 = r.gen_ascii_str(100);
201 assert_eq!(string1, string2);
202 }
203
204 static fill_bytes_v_len: uint = 13579;
205 #[test]
206 fn test_rng_fill_bytes() {
207 use task_rng;
208 let mut v = Vec::from_elem(fill_bytes_v_len, 0u8);
209 task_rng().fill_bytes(v.as_mut_slice());
210
211 // Sanity test: if we've gotten here, `fill_bytes` has not infinitely
212 // recursed.
213 assert_eq!(v.len(), fill_bytes_v_len);
214
215 // To test that `fill_bytes` actually did something, check that the
216 // average of `v` is not 0.
217 let mut sum = 0.0;
218 for &x in v.iter() {
219 sum += x as f64;
220 }
221 assert!(sum / v.len() as f64 != 0.0);
222 }
223 }
librand/reseeding.rs:22:52-22:52 -struct- definition:
/// has generated a certain number of random bytes.
pub struct ReseedingRng<R, Rsdr> {
rng: R,
references:- 839: pub fn new(rng: R, generation_threshold: uint, reseeder: Rsdr) -> ReseedingRng<R,Rsdr> {
40: ReseedingRng {
41: rng: rng,
--
88: fn from_seed((rsdr, seed): (Rsdr, S)) -> ReseedingRng<R, Rsdr> {
89: ReseedingRng {
90: rng: SeedableRng::from_seed(seed),
librand/lib.rs:
566: static TASK_RNG_RESEED_THRESHOLD: uint = 32_768;
567: type TaskRngInner = reseeding::ReseedingRng<StdRng, TaskRngReseeder>;
568: /// The task-local RNG.
librand/reseeding.rs:
38: /// * `reseeder`: the reseeding object to use.
39: pub fn new(rng: R, generation_threshold: uint, reseeder: Rsdr) -> ReseedingRng<R,Rsdr> {
40: ReseedingRng {
librand/reseeding.rs:124:8-124:8 -trait- definition:
/// ```
pub trait Reseeder<R> {
/// Reseed the given RNG.
references:- 531: impl<R: Rng, Rsdr: Reseeder<R>> ReseedingRng<R, Rsdr> {
32: /// Create a new `ReseedingRng` with the given parameters.
--
134: impl<R: Rng + Default> Reseeder<R> for ReseedWithDefault {
135: fn reseed(&mut self, rng: &mut R) {
librand/lib.rs:
558: impl reseeding::Reseeder<StdRng> for TaskRngReseeder {
559: fn reseed(&mut self, rng: &mut StdRng) {
librand/reseeding.rs:
59: impl<R: Rng, Rsdr: Reseeder<R>> Rng for ReseedingRng<R, Rsdr> {
60: fn next_u32(&mut self) -> u32 {
librand/reseeding.rs:131:68-131:68 -struct- definition:
/// replacing the RNG with the result of a `Default::default` call.
pub struct ReseedWithDefault;
impl<R: Rng + Default> Reseeder<R> for ReseedWithDefault {
references:- 3138: }
139: impl Default for ReseedWithDefault {
140: fn default() -> ReseedWithDefault { ReseedWithDefault }
141: }