use crate::RngCore;
#[allow(unused)]
use crate::SeedableRng;
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)
}
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)
}
#[inline]
#[track_caller]
pub fn read_u32_into(src: &[u8], dst: &mut [u32]) {
assert!(src.len() >= 4 * dst.len());
for (out, chunk) in dst.iter_mut().zip(src.chunks_exact(4)) {
*out = u32::from_le_bytes(chunk.try_into().unwrap());
}
}
#[inline]
#[track_caller]
pub fn read_u64_into(src: &[u8], dst: &mut [u64]) {
assert!(src.len() >= 8 * dst.len());
for (out, chunk) in dst.iter_mut().zip(src.chunks_exact(8)) {
*out = u64::from_le_bytes(chunk.try_into().unwrap());
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_fill_via_u32_chunks() {
let src_orig = [1u32, 2, 3];
let src = src_orig;
let mut dst = [0u8; 11];
assert_eq!(fill_via_chunks(&src, &mut dst), (3, 11));
assert_eq!(dst, [1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0]);
let src = src_orig;
let mut dst = [0u8; 13];
assert_eq!(fill_via_chunks(&src, &mut dst), (3, 12));
assert_eq!(dst, [1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0]);
let src = src_orig;
let mut dst = [0u8; 5];
assert_eq!(fill_via_chunks(&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 src = src_orig;
let mut dst = [0u8; 11];
assert_eq!(fill_via_chunks(&src, &mut dst), (2, 11));
assert_eq!(dst, [1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0]);
let src = src_orig;
let mut dst = [0u8; 17];
assert_eq!(fill_via_chunks(&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 src = src_orig;
let mut dst = [0u8; 5];
assert_eq!(fill_via_chunks(&src, &mut dst), (1, 5));
assert_eq!(dst, [1, 0, 0, 0, 0]);
}
#[test]
fn test_read() {
let bytes = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
let mut buf = [0u32; 4];
read_u32_into(&bytes, &mut buf);
assert_eq!(buf[0], 0x04030201);
assert_eq!(buf[3], 0x100F0E0D);
let mut buf = [0u32; 3];
read_u32_into(&bytes[1..13], &mut buf); assert_eq!(buf[0], 0x05040302);
assert_eq!(buf[2], 0x0D0C0B0A);
let mut buf = [0u64; 2];
read_u64_into(&bytes, &mut buf);
assert_eq!(buf[0], 0x0807060504030201);
assert_eq!(buf[1], 0x100F0E0D0C0B0A09);
let mut buf = [0u64; 1];
read_u64_into(&bytes[7..15], &mut buf); assert_eq!(buf[0], 0x0F0E0D0C0B0A0908);
}
}