use core::intrinsics::transmute;
use core::ptr::copy_nonoverlapping;
use core::slice;
use core::cmp::min;
use core::mem::size_of;
use RngCore;
pub fn next_u64_via_u32<R: RngCore + ?Sized>(rng: &mut R) -> u64 {
let x = u64::from(rng.next_u32());
let y = u64::from(rng.next_u32());
(y << 32) | x
}
pub fn fill_bytes_via_next<R: RngCore + ?Sized>(rng: &mut R, dest: &mut [u8]) {
let mut left = dest;
while left.len() >= 8 {
let (l, r) = {left}.split_at_mut(8);
left = r;
let chunk: [u8; 8] = unsafe {
transmute(rng.next_u64().to_le())
};
l.copy_from_slice(&chunk);
}
let n = left.len();
if n > 4 {
let chunk: [u8; 8] = unsafe {
transmute(rng.next_u64().to_le())
};
left.copy_from_slice(&chunk[..n]);
} else if n > 0 {
let chunk: [u8; 4] = unsafe {
transmute(rng.next_u32().to_le())
};
left.copy_from_slice(&chunk[..n]);
}
}
macro_rules! impl_uint_from_fill {
($rng:expr, $ty:ty, $N:expr) => ({
debug_assert!($N == size_of::<$ty>());
let mut int: $ty = 0;
unsafe {
let ptr = &mut int as *mut $ty as *mut u8;
let slice = slice::from_raw_parts_mut(ptr, $N);
$rng.fill_bytes(slice);
}
int
});
}
macro_rules! fill_via_chunks {
($src:expr, $dst:expr, $ty:ty, $size:expr) => ({
let chunk_size_u8 = min($src.len() * $size, $dst.len());
let chunk_size = (chunk_size_u8 + $size - 1) / $size;
if cfg!(target_endian="little") {
unsafe {
copy_nonoverlapping(
$src.as_ptr() as *const u8,
$dst.as_mut_ptr(),
chunk_size_u8);
}
} else {
for (&n, chunk) in $src.iter().zip($dst.chunks_mut($size)) {
let tmp = n.to_le();
let src_ptr = &tmp as *const $ty as *const u8;
unsafe {
copy_nonoverlapping(src_ptr,
chunk.as_mut_ptr(),
chunk.len());
}
}
}
(chunk_size, chunk_size_u8)
});
}
pub fn fill_via_u32_chunks(src: &[u32], dest: &mut [u8]) -> (usize, usize) {
fill_via_chunks!(src, dest, u32, 4)
}
pub fn fill_via_u64_chunks(src: &[u64], dest: &mut [u8]) -> (usize, usize) {
fill_via_chunks!(src, dest, u64, 8)
}
pub fn next_u32_via_fill<R: RngCore + ?Sized>(rng: &mut R) -> u32 {
impl_uint_from_fill!(rng, u32, 4)
}
pub fn next_u64_via_fill<R: RngCore + ?Sized>(rng: &mut R) -> u64 {
impl_uint_from_fill!(rng, u64, 8)
}