diff options
| author | Huon Wilson <dbau.pp+github@gmail.com> | 2013-09-22 20:51:57 +1000 |
|---|---|---|
| committer | Huon Wilson <dbau.pp+github@gmail.com> | 2013-10-09 22:22:42 +1100 |
| commit | 39a69d323da95ce642ea7fe8d40eb8bdd6a277c8 (patch) | |
| tree | 00c17e0dc840f82fe747dfd1265282209e0005f0 /src/libstd/rand/reader.rs | |
| parent | a2b509656ac9c0f98d89fe4ea9d2f64a6ec7047a (diff) | |
| download | rust-39a69d323da95ce642ea7fe8d40eb8bdd6a277c8.tar.gz rust-39a69d323da95ce642ea7fe8d40eb8bdd6a277c8.zip | |
std::rand: Add OSRng, ReaderRng wrappers around the OS RNG & generic Readers respectively.
The former reads from e.g. /dev/urandom, the latter just wraps any std::rt::io::Reader into an interface that implements Rng. This also adds Rng.fill_bytes for efficient implementations of the above (reading 8 bytes at a time is inefficient when you can read 1000), and removes the dependence on src/rt (i.e. rand_gen_seed) although this last one requires implementing hand-seeding of the XorShiftRng used in the scheduler on Linux/unixes, since OSRng relies on a scheduler existing to be able to read from /dev/urandom.
Diffstat (limited to 'src/libstd/rand/reader.rs')
| -rw-r--r-- | src/libstd/rand/reader.rs | 94 |
1 files changed, 94 insertions, 0 deletions
diff --git a/src/libstd/rand/reader.rs b/src/libstd/rand/reader.rs new file mode 100644 index 00000000000..f1164346fe6 --- /dev/null +++ b/src/libstd/rand/reader.rs @@ -0,0 +1,94 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use rt::io::Reader; +use rt::io::ReaderByteConversions; + +use rand::Rng; + +/// An RNG that reads random bytes straight from a `Reader`. This will +/// work best with an infinite reader, but this is not required. The +/// semantics of reading past the end of the reader are the same as +/// those of the `read` method of the inner `Reader`. +pub struct ReaderRng<R> { + priv reader: R +} + +impl<R: Reader> ReaderRng<R> { + /// Create a new `ReaderRng` from a `Reader`. + pub fn new(r: R) -> ReaderRng<R> { + ReaderRng { + reader: r + } + } +} + +impl<R: Reader> Rng for ReaderRng<R> { + fn next_u32(&mut self) -> u32 { + // XXX which is better: consistency between big/little-endian + // platforms, or speed. + if cfg!(target_endian="little") { + self.reader.read_le_u32_() + } else { + self.reader.read_be_u32_() + } + } + fn next_u64(&mut self) -> u64 { + if cfg!(target_endian="little") { + self.reader.read_le_u64_() + } else { + self.reader.read_be_u64_() + } + } + fn fill_bytes(&mut self, v: &mut [u8]) { + // XXX: check that we filled `v`` + let _n = self.reader.read(v); + } +} + +#[cfg(test)] +mod test { + use super::*; + use rt::io::mem::MemReader; + use cast; + + #[test] + fn test_reader_rng_u64() { + // transmute from the target to avoid endianness concerns. + let v = ~[1u64, 2u64, 3u64]; + let bytes: ~[u8] = unsafe {cast::transmute(v)}; + let mut rng = ReaderRng::new(MemReader::new(bytes)); + + assert_eq!(rng.next_u64(), 1); + assert_eq!(rng.next_u64(), 2); + assert_eq!(rng.next_u64(), 3); + } + #[test] + fn test_reader_rng_u32() { + // transmute from the target to avoid endianness concerns. + let v = ~[1u32, 2u32, 3u32]; + let bytes: ~[u8] = unsafe {cast::transmute(v)}; + let mut rng = ReaderRng::new(MemReader::new(bytes)); + + assert_eq!(rng.next_u32(), 1); + assert_eq!(rng.next_u32(), 2); + assert_eq!(rng.next_u32(), 3); + } + #[test] + fn test_reader_rng_fill_bytes() { + let v = [1u8, 2, 3, 4, 5, 6, 7, 8]; + let mut w = [0u8, .. 8]; + + let mut rng = ReaderRng::new(MemReader::new(v.to_owned())); + rng.fill_bytes(w); + + assert_eq!(v, w); + } +} |
