]> git.proxmox.com Git - rustc.git/blame - src/librand/reseeding.rs
Imported Upstream version 1.0.0-alpha.2
[rustc.git] / src / librand / reseeding.rs
CommitLineData
1a4d82fc
JJ
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
14use core::prelude::*;
15
16use {Rng, SeedableRng};
17use core::default::Default;
18
19/// How many bytes of entropy the underling RNG is allowed to generate
20/// before it is reseeded.
21static 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.
25pub 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
33impl<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
61impl<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
81impl<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/// ```
129pub 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)]
85aaf69f
SL
137pub struct ReseedWithDefault { __hack: [u8; 0] }
138// FIXME(#21721) used to be an unit struct but that can cause
139// certain LLVM versions to abort during optimizations.
140#[allow(non_upper_case_globals)]
141pub const ReseedWithDefault: ReseedWithDefault = ReseedWithDefault { __hack: [] };
1a4d82fc
JJ
142
143impl<R: Rng + Default> Reseeder<R> for ReseedWithDefault {
144 fn reseed(&mut self, rng: &mut R) {
145 *rng = Default::default();
146 }
147}
85aaf69f 148#[stable(feature = "rust1", since = "1.0.0")]
1a4d82fc 149impl Default for ReseedWithDefault {
85aaf69f 150 #[stable(feature = "rust1", since = "1.0.0")]
1a4d82fc
JJ
151 fn default() -> ReseedWithDefault { ReseedWithDefault }
152}
153
154#[cfg(test)]
155mod test {
156 use std::prelude::v1::*;
157
158 use core::iter::{order, repeat};
159 use super::{ReseedingRng, ReseedWithDefault};
160 use std::default::Default;
161 use {SeedableRng, Rng};
162
163 struct Counter {
164 i: u32
165 }
166
167 impl Rng for Counter {
168 fn next_u32(&mut self) -> u32 {
169 self.i += 1;
170 // very random
171 self.i - 1
172 }
173 }
174 impl Default for Counter {
175 fn default() -> Counter {
176 Counter { i: 0 }
177 }
178 }
179 impl SeedableRng<u32> for Counter {
180 fn reseed(&mut self, seed: u32) {
181 self.i = seed;
182 }
183 fn from_seed(seed: u32) -> Counter {
184 Counter { i: seed }
185 }
186 }
187 type MyRng = ReseedingRng<Counter, ReseedWithDefault>;
188
189 #[test]
190 fn test_reseeding() {
191 let mut rs = ReseedingRng::new(Counter {i:0}, 400, ReseedWithDefault);
192
193 let mut i = 0;
85aaf69f 194 for _ in 0..1000 {
1a4d82fc
JJ
195 assert_eq!(rs.next_u32(), i % 100);
196 i += 1;
197 }
198 }
199
200 #[test]
201 fn test_rng_seeded() {
202 let mut ra: MyRng = SeedableRng::from_seed((ReseedWithDefault, 2));
203 let mut rb: MyRng = SeedableRng::from_seed((ReseedWithDefault, 2));
204 assert!(order::equals(ra.gen_ascii_chars().take(100),
205 rb.gen_ascii_chars().take(100)));
206 }
207
208 #[test]
209 fn test_rng_reseed() {
210 let mut r: MyRng = SeedableRng::from_seed((ReseedWithDefault, 3));
211 let string1: String = r.gen_ascii_chars().take(100).collect();
212
213 r.reseed((ReseedWithDefault, 3));
214
215 let string2: String = r.gen_ascii_chars().take(100).collect();
216 assert_eq!(string1, string2);
217 }
218
219 static FILL_BYTES_V_LEN: uint = 13579;
220 #[test]
221 fn test_rng_fill_bytes() {
222 let mut v = repeat(0u8).take(FILL_BYTES_V_LEN).collect::<Vec<_>>();
85aaf69f 223 ::test::rng().fill_bytes(&mut v);
1a4d82fc
JJ
224
225 // Sanity test: if we've gotten here, `fill_bytes` has not infinitely
226 // recursed.
227 assert_eq!(v.len(), FILL_BYTES_V_LEN);
228
229 // To test that `fill_bytes` actually did something, check that the
230 // average of `v` is not 0.
231 let mut sum = 0.0;
85aaf69f 232 for &x in &v {
1a4d82fc
JJ
233 sum += x as f64;
234 }
235 assert!(sum / v.len() as f64 != 0.0);
236 }
237}