Skip to content

Commit e9d0b06

Browse files
committed
Add fill and try_fill methods to Rng
1 parent 18e8e91 commit e9d0b06

File tree

1 file changed

+140
-1
lines changed

1 file changed

+140
-1
lines changed

src/lib.rs

+140-1
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@
262262
#[cfg(all(feature="std", not(feature = "log")))] macro_rules! error { ($($x:tt)*) => () }
263263

264264

265-
use core::{marker, mem};
265+
use core::{marker, mem, slice};
266266
#[cfg(feature="std")] use std::cell::RefCell;
267267
#[cfg(feature="std")] use std::rc::Rc;
268268
#[cfg(all(feature="alloc", not(feature="std")))] use alloc::boxed::Box;
@@ -538,6 +538,71 @@ pub trait RngCore {
538538
///
539539
/// [`RngCore`]: trait.RngCore.html
540540
pub trait Rng: RngCore + Sized {
541+
/// Fill `dest` entirely with random bytes, where `dest` is any type
542+
/// supporting [`AsByteSliceMut`], namely slices over primitive integer
543+
/// types (`i8`, `i16`, `u32`, etc.).
544+
///
545+
/// On big-endian platforms this performs byte-swapping to ensure
546+
/// portability of results from reproducible generators.
547+
///
548+
/// This uses [`fill_bytes`] internally which may handle some RNG errors
549+
/// implicitly (e.g. waiting if the OS generator is not ready), but panics
550+
/// on other errors. See also [`try_fill`] which returns errors.
551+
///
552+
/// # Example
553+
///
554+
/// ```rust
555+
/// use rand::{thread_rng, Rng};
556+
///
557+
/// let mut arr = [0i8; 20];
558+
/// thread_rng().try_fill(&mut arr[..]);
559+
/// ```
560+
///
561+
/// [`fill_bytes`]: trait.RngCore.html#method.fill_bytes
562+
/// [`try_fill`]: trait.Rng.html#method.try_fill
563+
/// [`AsByteSliceMut`]: trait.AsByteSliceMut.html
564+
fn fill<T: AsByteSliceMut + ?Sized>(&mut self, dest: &mut T) where Self: Sized {
565+
self.fill_bytes(dest.as_byte_slice_mut());
566+
dest.to_le();
567+
}
568+
569+
/// Fill `dest` entirely with random bytes, where `dest` is any type
570+
/// supporting [`AsByteSliceMut`], namely slices over primitive integer
571+
/// types (`i8`, `i16`, `u32`, etc.).
572+
///
573+
/// On big-endian platforms this performs byte-swapping to ensure
574+
/// portability of results from reproducible generators.
575+
///
576+
/// This uses [`try_fill_bytes`] internally and forwards all RNG errors. In
577+
/// some cases errors may be resolvable; see [`ErrorKind`] and
578+
/// documentation for the RNG in use. If you do not plan to handle these
579+
/// errors you may prefer to use [`fill`].
580+
///
581+
/// # Example
582+
///
583+
/// ```rust
584+
/// # use rand::Error;
585+
/// use rand::{thread_rng, Rng};
586+
///
587+
/// # fn try_inner() -> Result<(), Error> {
588+
/// let mut arr = [0u64; 4];
589+
/// thread_rng().try_fill(&mut arr[..])?;
590+
/// # Ok(())
591+
/// # }
592+
///
593+
/// # try_inner().unwrap()
594+
/// ```
595+
///
596+
/// [`ErrorKind`]: enum.ErrorKind.html
597+
/// [`try_fill_bytes`]: trait.RngCore.html#method.try_fill_bytes
598+
/// [`fill`]: trait.Rng.html#method.fill
599+
/// [`AsByteSliceMut`]: trait.AsByteSliceMut.html
600+
fn try_fill<T: AsByteSliceMut + ?Sized>(&mut self, dest: &mut T) -> Result<(), Error> where Self: Sized {
601+
self.try_fill_bytes(dest.as_byte_slice_mut())?;
602+
dest.to_le();
603+
Ok(())
604+
}
605+
541606
/// Return a random value of a `Rand` type.
542607
///
543608
/// # Example
@@ -759,6 +824,62 @@ impl<R: RngCore + ?Sized> RngCore for Box<R> {
759824
}
760825
}
761826

827+
/// Trait for casting types to byte slices
828+
///
829+
/// This is used by the [`fill`] and [`try_fill`] methods.
830+
///
831+
/// [`fill`]: trait.Rng.html#method.fill
832+
/// [`try_fill`]: trait.Rng.html#method.try_fill
833+
pub trait AsByteSliceMut {
834+
/// Return a mutable reference to self as a byte slice
835+
fn as_byte_slice_mut<'a>(&'a mut self) -> &'a mut [u8];
836+
837+
/// Call `to_le` on each element (i.e. byte-swap on Big Endian platforms).
838+
fn to_le(&mut self);
839+
}
840+
841+
impl AsByteSliceMut for [u8] {
842+
fn as_byte_slice_mut<'a>(&'a mut self) -> &'a mut [u8] {
843+
self
844+
}
845+
846+
fn to_le(&mut self) {}
847+
}
848+
849+
macro_rules! impl_as_byte_slice {
850+
($t:ty) => {
851+
impl AsByteSliceMut for [$t] {
852+
fn as_byte_slice_mut<'a>(&'a mut self) -> &'a mut [u8] {
853+
unsafe {
854+
slice::from_raw_parts_mut(&mut self[0]
855+
as *mut $t
856+
as *mut u8,
857+
self.len() * mem::size_of::<$t>()
858+
)
859+
}
860+
}
861+
862+
fn to_le(&mut self) {
863+
for mut x in self {
864+
*x = x.to_le();
865+
}
866+
}
867+
}
868+
}
869+
}
870+
871+
impl_as_byte_slice!(u16);
872+
impl_as_byte_slice!(u32);
873+
impl_as_byte_slice!(u64);
874+
#[cfg(feature="i128_support")] impl_as_byte_slice!(u128);
875+
impl_as_byte_slice!(usize);
876+
impl_as_byte_slice!(i8);
877+
impl_as_byte_slice!(i16);
878+
impl_as_byte_slice!(i32);
879+
impl_as_byte_slice!(i64);
880+
#[cfg(feature="i128_support")] impl_as_byte_slice!(i128);
881+
impl_as_byte_slice!(isize);
882+
762883
/// Iterator which will generate a stream of random items.
763884
///
764885
/// This iterator is created via the [`gen_iter`] method on [`Rng`].
@@ -1364,6 +1485,24 @@ mod test {
13641485
}
13651486
}
13661487
}
1488+
1489+
#[test]
1490+
fn test_fill() {
1491+
let x = 9041086907909331047; // a random u64
1492+
let mut rng = ConstRng { i: x };
1493+
1494+
// Convert to byte sequence and back to u64; byte-swap twice if BE.
1495+
let mut array = [0u64; 2];
1496+
rng.fill(&mut array[..]);
1497+
assert_eq!(array, [x, x]);
1498+
assert_eq!(rng.next_u64(), x);
1499+
1500+
// Convert to bytes then u32 in LE order
1501+
let mut array = [0u32; 2];
1502+
rng.fill(&mut array[..]);
1503+
assert_eq!(array, [x as u32, (x >> 32) as u32]);
1504+
assert_eq!(rng.next_u32(), x as u32);
1505+
}
13671506

13681507
#[test]
13691508
fn test_gen_range() {

0 commit comments

Comments
 (0)