Skip to content

Commit

Permalink
Add fill and try_fill methods to Rng
Browse files Browse the repository at this point in the history
  • Loading branch information
dhardy committed Feb 4, 2018
1 parent 7d72ba9 commit 93a80bd
Showing 1 changed file with 119 additions and 1 deletion.
120 changes: 119 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@
#[cfg(all(feature="std", not(feature = "log")))] macro_rules! warn { ($($x:tt)*) => () }


use core::{marker, mem};
use core::{marker, mem, slice};
#[cfg(feature="std")] use std::cell::RefCell;
#[cfg(feature="std")] use std::rc::Rc;
#[cfg(all(feature="alloc", not(feature="std")))] use alloc::boxed::Box;
Expand Down Expand Up @@ -482,6 +482,66 @@ pub trait Rng {
Ok(self.fill_bytes(dest))
}

/// Fill `dest` entirely with random data.
///
/// This method provides a convenient way to fill a slice with random data.
///
/// On big-endian platforms this performs byte-swapping to ensure
/// portability of results from reproducible generators.
///
/// # Example
///
/// ```rust
/// use rand::{thread_rng, Rng};
///
/// let mut arr = [0i8; 20];
/// thread_rng().try_fill(&mut arr[..]);
/// ```
///
/// [`ErrorKind`]: enum.ErrorKind.html
fn fill<T: AsByteSliceMut + ?Sized>(&mut self, dest: &mut T) where Self: Sized {
let slice = dest.as_byte_slice_mut();
self.fill_bytes(slice);
for mut x in slice {
x.to_le();
}
}

/// Fill `dest` entirely with random data.
///
/// This method provides a convenient way to fill a slice with random data.
///
/// On big-endian platforms this performs byte-swapping to ensure
/// portability of results from reproducible generators.
///
/// Errors are forwarded from their source. In some cases errors may be
/// resolvable; see [`ErrorKind`] and documentation for the RNG in use.
///
/// # Example
///
/// ```rust
/// # use rand::Error;
/// use rand::{thread_rng, Rng};
///
/// # fn try_inner() -> Result<(), Error> {
/// let mut arr = [0u64; 4];
/// thread_rng().try_fill(&mut arr[..])?;
/// # Ok(())
/// # }
///
/// # try_inner().unwrap()
/// ```
///
/// [`ErrorKind`]: enum.ErrorKind.html
fn try_fill<T: AsByteSliceMut + ?Sized>(&mut self, dest: &mut T) -> Result<(), Error> where Self: Sized {
let slice = dest.as_byte_slice_mut();
self.try_fill_bytes(slice)?;
for mut x in slice {
x.to_le();
}
Ok(())
}

/// Return a random value of a `Rand` type.
///
/// # Example
Expand Down Expand Up @@ -701,6 +761,46 @@ impl<R: ?Sized> Rng for Box<R> where R: Rng {
}
}

/// Trait for casting types to byte slices
pub trait AsByteSliceMut {
/// Return a mutable reference to self as a byte slice
fn as_byte_slice_mut<'a>(&'a mut self) -> &'a mut [u8];
}

impl AsByteSliceMut for [u8] {
fn as_byte_slice_mut<'a>(&'a mut self) -> &'a mut [u8] {
self
}
}

macro_rules! impl_as_byte_slice {
($t:ty) => {
impl AsByteSliceMut for [$t] {
fn as_byte_slice_mut<'a>(&'a mut self) -> &'a mut [u8] {
unsafe {
slice::from_raw_parts_mut(&mut self[0]
as *mut $t
as *mut u8,
self.len() * mem::size_of::<$t>()
)
}
}
}
}
}

impl_as_byte_slice!(u16);
impl_as_byte_slice!(u32);
impl_as_byte_slice!(u64);
#[cfg(feature="i128_support")] impl_as_byte_slice!(u128);
impl_as_byte_slice!(usize);
impl_as_byte_slice!(i8);
impl_as_byte_slice!(i16);
impl_as_byte_slice!(i32);
impl_as_byte_slice!(i64);
#[cfg(feature="i128_support")] impl_as_byte_slice!(i128);
impl_as_byte_slice!(isize);

/// Iterator which will generate a stream of random items.
///
/// This iterator is created via the [`gen_iter`] method on [`Rng`].
Expand Down Expand Up @@ -1162,6 +1262,24 @@ mod test {
}
}
}

#[test]
fn test_fill() {
let x = 9041086907909331047; // a random u64
let mut rng = ConstRng { i: x };

// Convert to byte sequence and back to u64; byte-swap twice if BE.
let mut array = [0u64; 2];
rng.fill(&mut array[..]);
assert_eq!(array, [x, x]);
assert_eq!(rng.next_u64(), x);

// Convert to bytes then u32 in LE order
let mut array = [0u32; 2];
rng.fill(&mut array[..]);
assert_eq!(array, [x as u32, (x >> 32) as u32]);
assert_eq!(rng.next_u32(), x as u32);
}

#[test]
fn test_gen_range() {
Expand Down

0 comments on commit 93a80bd

Please sign in to comment.