Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace convert_slice_{32,64} with read_u{32,64}_into #77

Merged
merged 2 commits into from
Dec 27, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion benches/generators.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const BYTES_LEN: usize = 1024;
use std::mem::size_of;
use test::{black_box, Bencher};

use rand::{Rng, NewSeeded, Sample, SeedFromRng, StdRng, OsRng, JitterRng};
use rand::{Rng, NewSeeded, Sample, SeedableRng, StdRng, OsRng, JitterRng};
use rand::prng::*;

macro_rules! gen_bytes {
Expand Down
155 changes: 67 additions & 88 deletions rand_core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ extern crate core;
#[cfg(feature="std")]
use std::error::Error as stdError;

use core::fmt;
use core::{fmt, slice, mem};

pub mod impls;

Expand Down Expand Up @@ -206,69 +206,66 @@ impl<R: Rng+?Sized> Rng for Box<R> {
}


/// Support mechanism for creating random number generators seeded by other
/// generators. All PRNGs should support this to enable `NewSeeded` support,
/// which should be the preferred way of creating randomly-seeded generators.
///
/// There are two subtle differences between `SeedFromRng::from_rng` and
/// `SeedableRng::from_seed` (beyond the obvious): first, that `from_rng` has
/// no reproducibility requirement, and second, that `from_rng` may directly
/// fill internal states larger than `SeedableRng::Seed`, where `from_seed` may
/// need some extra step to expand the input.
pub trait SeedFromRng: Sized {
/// Creates a new instance, seeded from another `Rng`.
///
/// Seeding from a cryptographic generator should be fine. On the other
/// hand, seeding a simple numerical generator from another of the same
/// type sometimes has serious side effects such as effectively cloning the
/// generator.
fn from_rng<R: Rng>(rng: R) -> Result<Self, Error>;
}

mod private {
pub trait Sealed {}
impl<S> Sealed for S where S: super::SeedRestriction {}
}

/// The seed type is restricted to these types. This trait is sealed to prevent
/// user-extension.
///
///
/// Use of byte-arrays avoids endianness issues. We may extend this to allow
/// byte arrays of other lengths in the future.
pub trait SeedRestriction: private::Sealed {}
pub trait SeedRestriction: private::Sealed +
::core::default::Default +
::core::convert::AsMut<[u8]> {}
impl SeedRestriction for [u8; 8] {}
impl SeedRestriction for [u8; 16] {}
impl SeedRestriction for [u8; 32] {}

/// A random number generator that can be explicitly seeded to produce
/// the same stream of randomness multiple times (i.e. is reproducible).
///
/// Note: this should only be implemented by reproducible generators (i.e.
/// where the algorithm is fixed and results should be the same across
/// platforms). This should not be implemented by wrapper types which choose
/// the underlying implementation based on platform, or which may change the
/// algorithm used in the future. This is to ensure that manual seeding of PRNGs
/// actually does yield reproducible results.
/// A random number generator that can be explicitly seeded.
///
/// There are two subtle differences between `from_rng` and`from_seed` (beyond
/// the obvious): first, that `from_rng` has no reproducibility requirement, and
/// second, that `from_rng` may directly fill internal states larger than
/// `SeedableRng::Seed`, where `from_seed` may need some extra step to expand
/// the input.
pub trait SeedableRng: Sized {
/// Seed type.
type Seed: SeedRestriction;

/// Create a new PRNG using the given seed.
///
///
/// Each PRNG should implement this.
///
///
/// Reproducibility is required; that is, a fixed PRNG seeded using this
/// function with a fixed seed should produce the same sequence of output
/// today, and in the future. PRNGs not able to satisfy this should make
/// clear notes in their documentation or not implement `SeedableRng` at
/// all. It is however not required that this function yield the same state
/// as a reference implementation of the PRNG given equivalent seed; if
/// necessary another constructor should be used.
///
/// clear notes in their documentation. It is however not required that this
/// function yield the same state as a reference implementation of the PRNG
/// given equivalent seed; if necessary another constructor should be used.
///
/// It may be expected that bits in the seed are well distributed, i.e. that
/// values like 0, 1 and (size - 1) are unlikely. Users with poorly
/// distributed input should use `from_hashable`.
fn from_seed(seed: Self::Seed) -> Self;

/// Create a new PRNG seeded from another `Rng`.
///
/// Seeding from a cryptographic generator should be fine. On the other
/// hand, seeding a simple numerical generator from another of the same
/// type sometimes has serious side effects such as effectively cloning the
/// generator.
fn from_rng<R: Rng>(mut rng: R) -> Result<Self, Error> {
let mut seed = Self::Seed::default();
let size = mem::size_of::<Self::Seed>() as usize;
unsafe {
let ptr = seed.as_mut().as_mut_ptr() as *mut u8;
let slice = slice::from_raw_parts_mut(ptr, size);
rng.try_fill(slice)?;
}
Ok(Self::from_seed(seed))
}
}


Expand Down Expand Up @@ -396,69 +393,51 @@ impl stdError for Error {
/// Little-Endian order has been chosen for internal usage; this makes some
/// useful functions available.
pub mod le {
use core::slice;
use core::ptr;

/// Helper function to turn a slice into an array reference

/// Read a `u32` from a byte sequence, in litte-endian order
///
/// Consider usage with the `arrayref` crate.
pub fn read_u32(bytes: &[u8; 4]) -> u32 {
unsafe{ *(bytes as *const [u8; 4] as *const u32) }.to_le()
}

/// Read a `u64` from a byte sequence, in litte-endian order
///
/// Consider usage with the `arrayref` crate.
pub fn read_u64(bytes: &[u8; 8]) -> u64 {
unsafe{ *(bytes as *const [u8; 8] as *const u64) }.to_le()
}

/// Convert a byte slice to a `u32` slice and mutate endianness in-place
pub fn convert_slice_32(bytes: &mut [u8]) -> &mut [u32] {
assert_eq!(bytes.len() % 4, 0);
let l = bytes.len() / 4;
let p = bytes.as_ptr() as *mut u8 as *mut u32;
let s = unsafe{ slice::from_raw_parts_mut(p, l) };
for i in s.iter_mut() {
*i = (*i).to_le();
}
s
}

/// Convert a byte slice to a `u64` slice and mutate endianness in-place
pub fn convert_slice_64(bytes: &mut [u8]) -> &mut [u64] {
assert_eq!(bytes.len() % 8, 0);
let l = bytes.len() / 8;
let p = bytes.as_ptr() as *mut u8 as *mut u64;
let s = unsafe{ slice::from_raw_parts_mut(p, l) };
for i in s.iter_mut() {
*i = (*i).to_le();
}
s
}

#[cfg(test)]
mod tests {
use super::*;
#[test]

fn test_read() {
assert_eq!(read_u32(&[1, 2, 3, 4]), 0x04030201);
assert_eq!(read_u64(&[1, 2, 3, 4, 5, 6, 7, 8]), 0x0807060504030201);

{
let mut bytes = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
let slice = convert_slice_32(&mut bytes[..]);
assert_eq!(slice[0], 0x04030201);
assert_eq!(slice[3], 0x100F0E0D);

macro_rules! read_slice {
($src:expr, $dst:expr, $size:expr, $which:ident) => {{
assert_eq!($src.len(), $size * $dst.len());

unsafe {
ptr::copy_nonoverlapping(
$src.as_ptr(),
$dst.as_mut_ptr() as *mut u8,
$src.len());
}
{
let mut bytes = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
let slice = convert_slice_64(&mut bytes[..]);
assert_eq!(slice[0], 0x0807060504030201);
assert_eq!(slice[1], 0x100F0E0D0C0B0A09);
for v in $dst.iter_mut() {
*v = v.$which();
}
}
}};
}

/// Reads unsigned 32 bit integers from `src` into `dst`.
/// Borrowed from the `byteorder` crate.
#[inline]
pub fn read_u32_into(src: &[u8], dst: &mut [u32]) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code looks fine. Oh, you copied the name from byteorder? I guess it'll do.

read_slice!(src, dst, 4, to_le);
}

/// Reads unsigned 64 bit integers from `src` into `dst`.
/// Borrowed from the `byteorder` crate.
#[inline]
pub fn read_u64_into(src: &[u8], dst: &mut [u64]) {
read_slice!(src, dst, 8, to_le);
}
}
40 changes: 21 additions & 19 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@
extern crate rand_core;

// core traits and types
pub use rand_core::{Rng, CryptoRng, SeedFromRng, SeedableRng, Error, ErrorKind};
pub use rand_core::{Rng, CryptoRng, SeedableRng, Error, ErrorKind};

// external rngs
pub use jitter::JitterRng;
Expand Down Expand Up @@ -315,11 +315,11 @@ mod thread_local;

/// Seeding mechanism for PRNGs, providing a `new` function.
/// This is the recommended way to create (pseudo) random number generators,
/// unless a deterministic seed is desired (in which case the `SeedableRng`
/// trait should be used directly).
/// unless a deterministic seed is desired (in which case
/// `SeedableRng::from_seed` should be used).
///
/// Note: this trait is automatically implemented for any PRNG implementing
/// `SeedFromRng` and is not intended to be implemented by users.
/// `SeedableRng` and is not intended to be implemented by users.
///
/// ## Example
///
Expand All @@ -330,7 +330,7 @@ mod thread_local;
/// println!("Random die roll: {}", rng.gen_range(1, 7));
/// ```
#[cfg(feature="std")]
pub trait NewSeeded: SeedFromRng {
pub trait NewSeeded: SeedableRng {
/// Creates a new instance, automatically seeded with fresh entropy.
///
/// Normally this will use `OsRng`, but if that fails `JitterRng` will be
Expand All @@ -340,14 +340,14 @@ pub trait NewSeeded: SeedFromRng {
}

#[cfg(feature="std")]
impl<R: SeedFromRng> NewSeeded for R {
impl<R: SeedableRng> NewSeeded for R {
fn new() -> Result<Self, Error> {
// Note: error handling would be easier with try/catch blocks
fn new_os<T: SeedFromRng>() -> Result<T, Error> {
fn new_os<T: SeedableRng>() -> Result<T, Error> {
let mut r = OsRng::new()?;
T::from_rng(&mut r)
}
fn new_jitter<T: SeedFromRng>() -> Result<T, Error> {
fn new_jitter<T: SeedableRng>() -> Result<T, Error> {
let mut r = JitterRng::new()?;
T::from_rng(&mut r)
}
Expand Down Expand Up @@ -461,32 +461,34 @@ impl<R: Rng+?Sized> Sample for R {
/// cannot be guaranteed to be reproducible. For this reason, `StdRng` does
/// not support `SeedableRng`.
#[derive(Clone, Debug)]
pub struct StdRng {
rng: IsaacWordRng,
}
pub struct StdRng(IsaacWordRng);

impl Rng for StdRng {
fn next_u32(&mut self) -> u32 {
self.rng.next_u32()
self.0.next_u32()
}
fn next_u64(&mut self) -> u64 {
self.rng.next_u64()
self.0.next_u64()
}
#[cfg(feature = "i128_support")]
fn next_u128(&mut self) -> u128 {
self.rng.next_u128()
self.0.next_u128()
}
fn fill_bytes(&mut self, dest: &mut [u8]) {
self.rng.fill_bytes(dest);
self.0.fill_bytes(dest);
}
fn try_fill(&mut self, dest: &mut [u8]) -> Result<(), Error> {
self.rng.try_fill(dest)
self.0.try_fill(dest)
}
}

impl SeedFromRng for StdRng {
fn from_rng<R: Rng>(other: R) -> Result<Self, Error> {
IsaacWordRng::from_rng(other).map(|rng| StdRng{ rng })
impl SeedableRng for StdRng {
type Seed = <IsaacWordRng as SeedableRng>::Seed;
fn from_seed(seed: Self::Seed) -> Self {
StdRng(IsaacWordRng::from_seed(seed))
}
fn from_rng<R: Rng>(rng: R) -> Result<Self, Error> {
IsaacWordRng::from_rng(rng).map(|rng| StdRng(rng))
}
}

Expand Down
Loading