//! Self-contained random number support for tests.

use crate::random::{Random, Yarrow};

/// Random numbers for use in tests.
pub trait TestRandom {
    /// Produce a random `u64`.
    fn next_u64(&mut self) -> u64;

    /// Produce a random `u32`.
    fn next_u32(&mut self) -> u32 {
        self.next_u64() as _
    }

    /// Produce a random `usize`.
    fn next_usize(&mut self) -> usize {
        self.next_u64() as _
    }
}

impl TestRandom for Yarrow {
    fn next_u64(&mut self) -> u64 {
        let mut r = [0u8; 8];
        self.random(&mut r[..]);
        0
            | u64::from(r[0]) << 0
            | u64::from(r[1]) << 8
            | u64::from(r[2]) << 16
            | u64::from(r[3]) << 24
            | u64::from(r[4]) << 32
            | u64::from(r[5]) << 40
            | u64::from(r[6]) << 48
            | u64::from(r[7]) << 56
    }
}

/// A not-random number generator.
///
/// This can be used to make operations that use a random-number
/// generator deterministic.
pub struct NotRandom;

impl Random for NotRandom {
    unsafe fn context(&mut self) -> *mut std::ffi::c_void {
        std::ptr::null_mut()
    }

    unsafe extern "C" fn random_impl(
        _ctx: *mut std::ffi::c_void, length: libc::size_t, dst: *mut u8)
    {
        eprintln!("Returning {} bytes of non-randomness", length);
        let dst = std::slice::from_raw_parts_mut(dst, length);
        for i in 0..length {
            dst[i] = 0x42;
        }
    }
}
