Skip to content

Commit d9bde36

Browse files
authored
Merge pull request #247 from dhardy/fill_rng
Add fill and try_fill methods to Rng
2 parents 8ce7435 + 5da66c3 commit d9bde36

File tree

2 files changed

+160
-3
lines changed

2 files changed

+160
-3
lines changed

src/lib.rs

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

267267

268-
use core::{marker, mem};
268+
use core::{marker, mem, slice};
269269
#[cfg(feature="std")] use std::cell::RefCell;
270270
#[cfg(feature="std")] use std::rc::Rc;
271271
#[cfg(all(feature="alloc", not(feature="std")))] use alloc::boxed::Box;
@@ -508,6 +508,71 @@ pub trait RngCore {
508508
///
509509
/// [`RngCore`]: trait.RngCore.html
510510
pub trait Rng: RngCore + Sized {
511+
/// Fill `dest` entirely with random bytes (uniform value distribution),
512+
/// where `dest` is any type supporting [`AsByteSliceMut`], namely slices
513+
/// and arrays over primitive integer types (`i8`, `i16`, `u32`, etc.).
514+
///
515+
/// On big-endian platforms this performs byte-swapping to ensure
516+
/// portability of results from reproducible generators.
517+
///
518+
/// This uses [`fill_bytes`] internally which may handle some RNG errors
519+
/// implicitly (e.g. waiting if the OS generator is not ready), but panics
520+
/// on other errors. See also [`try_fill`] which returns errors.
521+
///
522+
/// # Example
523+
///
524+
/// ```rust
525+
/// use rand::{thread_rng, Rng};
526+
///
527+
/// let mut arr = [0i8; 20];
528+
/// thread_rng().try_fill(&mut arr[..]);
529+
/// ```
530+
///
531+
/// [`fill_bytes`]: trait.RngCore.html#method.fill_bytes
532+
/// [`try_fill`]: trait.Rng.html#method.try_fill
533+
/// [`AsByteSliceMut`]: trait.AsByteSliceMut.html
534+
fn fill<T: AsByteSliceMut + ?Sized>(&mut self, dest: &mut T) where Self: Sized {
535+
self.fill_bytes(dest.as_byte_slice_mut());
536+
dest.to_le();
537+
}
538+
539+
/// Fill `dest` entirely with random bytes (uniform value distribution),
540+
/// where `dest` is any type supporting [`AsByteSliceMut`], namely slices
541+
/// and arrays over primitive integer types (`i8`, `i16`, `u32`, etc.).
542+
///
543+
/// On big-endian platforms this performs byte-swapping to ensure
544+
/// portability of results from reproducible generators.
545+
///
546+
/// This uses [`try_fill_bytes`] internally and forwards all RNG errors. In
547+
/// some cases errors may be resolvable; see [`ErrorKind`] and
548+
/// documentation for the RNG in use. If you do not plan to handle these
549+
/// errors you may prefer to use [`fill`].
550+
///
551+
/// # Example
552+
///
553+
/// ```rust
554+
/// # use rand::Error;
555+
/// use rand::{thread_rng, Rng};
556+
///
557+
/// # fn try_inner() -> Result<(), Error> {
558+
/// let mut arr = [0u64; 4];
559+
/// thread_rng().try_fill(&mut arr[..])?;
560+
/// # Ok(())
561+
/// # }
562+
///
563+
/// # try_inner().unwrap()
564+
/// ```
565+
///
566+
/// [`ErrorKind`]: enum.ErrorKind.html
567+
/// [`try_fill_bytes`]: trait.RngCore.html#method.try_fill_bytes
568+
/// [`fill`]: trait.Rng.html#method.fill
569+
/// [`AsByteSliceMut`]: trait.AsByteSliceMut.html
570+
fn try_fill<T: AsByteSliceMut + ?Sized>(&mut self, dest: &mut T) -> Result<(), Error> where Self: Sized {
571+
self.try_fill_bytes(dest.as_byte_slice_mut())?;
572+
dest.to_le();
573+
Ok(())
574+
}
575+
511576
/// Sample a new value, using the given distribution.
512577
///
513578
/// ### Example
@@ -746,6 +811,80 @@ impl<R: RngCore + ?Sized> RngCore for Box<R> {
746811
}
747812
}
748813

814+
/// Trait for casting types to byte slices
815+
///
816+
/// This is used by the [`fill`] and [`try_fill`] methods.
817+
///
818+
/// [`fill`]: trait.Rng.html#method.fill
819+
/// [`try_fill`]: trait.Rng.html#method.try_fill
820+
pub trait AsByteSliceMut {
821+
/// Return a mutable reference to self as a byte slice
822+
fn as_byte_slice_mut<'a>(&'a mut self) -> &'a mut [u8];
823+
824+
/// Call `to_le` on each element (i.e. byte-swap on Big Endian platforms).
825+
fn to_le(&mut self);
826+
}
827+
828+
impl AsByteSliceMut for [u8] {
829+
fn as_byte_slice_mut<'a>(&'a mut self) -> &'a mut [u8] {
830+
self
831+
}
832+
833+
fn to_le(&mut self) {}
834+
}
835+
836+
macro_rules! impl_as_byte_slice {
837+
($t:ty) => {
838+
impl AsByteSliceMut for [$t] {
839+
fn as_byte_slice_mut<'a>(&'a mut self) -> &'a mut [u8] {
840+
unsafe {
841+
slice::from_raw_parts_mut(&mut self[0]
842+
as *mut $t
843+
as *mut u8,
844+
self.len() * mem::size_of::<$t>()
845+
)
846+
}
847+
}
848+
849+
fn to_le(&mut self) {
850+
for mut x in self {
851+
*x = x.to_le();
852+
}
853+
}
854+
}
855+
}
856+
}
857+
858+
impl_as_byte_slice!(u16);
859+
impl_as_byte_slice!(u32);
860+
impl_as_byte_slice!(u64);
861+
#[cfg(feature="i128_support")] impl_as_byte_slice!(u128);
862+
impl_as_byte_slice!(usize);
863+
impl_as_byte_slice!(i8);
864+
impl_as_byte_slice!(i16);
865+
impl_as_byte_slice!(i32);
866+
impl_as_byte_slice!(i64);
867+
#[cfg(feature="i128_support")] impl_as_byte_slice!(i128);
868+
impl_as_byte_slice!(isize);
869+
870+
macro_rules! impl_as_byte_slice_arrays {
871+
($n:expr,) => {};
872+
($n:expr, $N:ident, $($NN:ident,)*) => {
873+
impl_as_byte_slice_arrays!($n - 1, $($NN,)*);
874+
875+
impl<T> AsByteSliceMut for [T; $n] where [T]: AsByteSliceMut {
876+
fn as_byte_slice_mut<'a>(&'a mut self) -> &'a mut [u8] {
877+
self[..].as_byte_slice_mut()
878+
}
879+
880+
fn to_le(&mut self) {
881+
self[..].to_le()
882+
}
883+
}
884+
};
885+
}
886+
impl_as_byte_slice_arrays!(32, N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,);
887+
749888
/// Iterator which will generate a stream of random items.
750889
///
751890
/// This iterator is created via the [`gen_iter`] method on [`Rng`].
@@ -1317,6 +1456,24 @@ mod test {
13171456
}
13181457
}
13191458
}
1459+
1460+
#[test]
1461+
fn test_fill() {
1462+
let x = 9041086907909331047; // a random u64
1463+
let mut rng = ConstRng { i: x };
1464+
1465+
// Convert to byte sequence and back to u64; byte-swap twice if BE.
1466+
let mut array = [0u64; 2];
1467+
rng.fill(&mut array[..]);
1468+
assert_eq!(array, [x, x]);
1469+
assert_eq!(rng.next_u64(), x);
1470+
1471+
// Convert to bytes then u32 in LE order
1472+
let mut array = [0u32; 2];
1473+
rng.fill(&mut array[..]);
1474+
assert_eq!(array, [x as u32, (x >> 32) as u32]);
1475+
assert_eq!(rng.next_u32(), x as u32);
1476+
}
13201477

13211478
#[test]
13221479
fn test_gen_range() {

src/seq.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ fn sample_indices_cache<R>(
227227
#[cfg(test)]
228228
mod test {
229229
use super::*;
230-
use {XorShiftRng, RngCore, SeedableRng};
230+
use {XorShiftRng, Rng, SeedableRng};
231231
#[cfg(not(feature="std"))]
232232
use alloc::Vec;
233233

@@ -304,7 +304,7 @@ mod test {
304304
for length in 1usize..max_range {
305305
let amount = r.gen_range(0, length);
306306
let mut seed = [0u8; 16];
307-
r.fill_bytes(&mut seed);
307+
r.fill(&mut seed);
308308

309309
// assert that the two index methods give exactly the same result
310310
let inplace = sample_indices_inplace(

0 commit comments

Comments
 (0)