use crate::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] = rng.next_u64().to_le_bytes();
l.copy_from_slice(&chunk);
}
let n = left.len();
if n > 4 {
let chunk: [u8; 8] = rng.next_u64().to_le_bytes();
left.copy_from_slice(&chunk[..n]);
} else if n > 0 {
let chunk: [u8; 4] = rng.next_u32().to_le_bytes();
left.copy_from_slice(&chunk[..n]);
}
}
pub(crate) trait Observable: Copy {
type Bytes: Sized + AsRef<[u8]>;
fn to_le_bytes(self) -> Self::Bytes;
}
impl Observable for u32 {
type Bytes = [u8; 4];
fn to_le_bytes(self) -> Self::Bytes {
Self::to_le_bytes(self)
}
}
impl Observable for u64 {
type Bytes = [u8; 8];
fn to_le_bytes(self) -> Self::Bytes {
Self::to_le_bytes(self)
}
}
pub(crate) fn fill_via_chunks<T: Observable>(src: &[T], dest: &mut [u8]) -> (usize, usize) {
let size = core::mem::size_of::<T>();
let mut dest = dest.chunks_exact_mut(size);
let mut src = src.iter();
let zipped = dest.by_ref().zip(src.by_ref());
let num_chunks = zipped.len();
zipped.for_each(|(dest, src)| dest.copy_from_slice(src.to_le_bytes().as_ref()));
let byte_len = num_chunks * size;
if let Some(src) = src.next() {
let dest = dest.into_remainder();
let n = dest.len();
if n > 0 {
dest.copy_from_slice(&src.to_le_bytes().as_ref()[..n]);
return (num_chunks + 1, byte_len + n);
}
}
(num_chunks, byte_len)
}
#[deprecated(since = "0.9.3", note = "use BlockRng instead")]
pub fn fill_via_u32_chunks(src: &mut [u32], dest: &mut [u8]) -> (usize, usize) {
fill_via_chunks(src, dest)
}
#[deprecated(since = "0.9.3", note = "use BlockRng64 instead")]
pub fn fill_via_u64_chunks(src: &mut [u64], dest: &mut [u8]) -> (usize, usize) {
fill_via_chunks(src, dest)
}
pub fn next_u32_via_fill<R: RngCore + ?Sized>(rng: &mut R) -> u32 {
let mut buf = [0; 4];
rng.fill_bytes(&mut buf);
u32::from_le_bytes(buf)
}
pub fn next_u64_via_fill<R: RngCore + ?Sized>(rng: &mut R) -> u64 {
let mut buf = [0; 8];
rng.fill_bytes(&mut buf);
u64::from_le_bytes(buf)
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_fill_via_u32_chunks() {
let src_orig = [1u32, 2, 3];
let mut src = src_orig;
let mut dst = [0u8; 11];
assert_eq!(fill_via_chunks(&mut src, &mut dst), (3, 11));
assert_eq!(dst, [1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0]);
let mut src = src_orig;
let mut dst = [0u8; 13];
assert_eq!(fill_via_chunks(&mut src, &mut dst), (3, 12));
assert_eq!(dst, [1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0]);
let mut src = src_orig;
let mut dst = [0u8; 5];
assert_eq!(fill_via_chunks(&mut src, &mut dst), (2, 5));
assert_eq!(dst, [1, 0, 0, 0, 2]);
}
#[test]
fn test_fill_via_u64_chunks() {
let src_orig = [1u64, 2];
let mut src = src_orig;
let mut dst = [0u8; 11];
assert_eq!(fill_via_chunks(&mut src, &mut dst), (2, 11));
assert_eq!(dst, [1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0]);
let mut src = src_orig;
let mut dst = [0u8; 17];
assert_eq!(fill_via_chunks(&mut src, &mut dst), (2, 16));
assert_eq!(dst, [1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0]);
let mut src = src_orig;
let mut dst = [0u8; 5];
assert_eq!(fill_via_chunks(&mut src, &mut dst), (1, 5));
assert_eq!(dst, [1, 0, 0, 0, 0]);
}
}