use alloc::boxed::Box;
use core::cell::RefCell;
use core::ops::Range;
use tinyrand::{Probability, Rand};
#[derive(Default)]
pub struct State {
next_u128_invocations: u64,
next_bool_invocations: u64,
next_lim_u128_invocations: u64,
}
impl State {
pub fn next_u128_invocations(&self) -> u64 {
self.next_u128_invocations
}
pub fn next_bool_invocations(&self) -> u64 {
self.next_bool_invocations
}
pub fn next_lim_u128_invocations(&self) -> u64 {
self.next_lim_u128_invocations
}
}
pub struct Surrogate<'a, 'd> {
state: &'a mut State,
next_u128_delegate: &'a mut Box<dyn FnMut(&State) -> u128 + 'd>,
}
impl Surrogate<'_, '_> {
pub fn state(&self) -> &State {
self.state
}
}
impl<'a, 'd> Rand for Surrogate<'a, 'd> {
fn next_u64(&mut self) -> u64 {
self.next_u128() as u64
}
fn next_u128(&mut self) -> u128 {
let r = (self.next_u128_delegate)(self.state);
self.state.next_u128_invocations += 1;
r
}
}
pub struct Mock<'d> {
state: State,
next_u128_delegate: Box<dyn FnMut(&State) -> u128 + 'd>,
next_bool_delegate: Box<dyn FnMut(Surrogate, Probability) -> bool + 'd>,
next_lim_u128_delegate: Box<dyn FnMut(Surrogate, u128) -> u128 + 'd>,
}
impl<'a> Default for Mock<'a> {
fn default() -> Self {
Self {
state: State::default(),
next_u128_delegate: Box::new(fixed(0)),
next_bool_delegate: Box::new(|mut surrogate, p| Rand::next_bool(&mut surrogate, p)),
next_lim_u128_delegate: Box::new(|mut surrogate, lim| {
Rand::next_lim_u128(&mut surrogate, lim)
}),
}
}
}
impl<'d> Mock<'d> {
#[must_use]
pub fn with_next_u128(mut self, delegate: impl FnMut(&State) -> u128 + 'd) -> Self {
self.next_u128_delegate = Box::new(delegate);
self
}
#[must_use]
pub fn with_next_bool(
mut self,
delegate: impl FnMut(Surrogate, Probability) -> bool + 'd,
) -> Self {
self.next_bool_delegate = Box::new(delegate);
self
}
#[must_use]
pub fn with_next_lim_u128(
mut self,
delegate: impl FnMut(Surrogate, u128) -> u128 + 'd,
) -> Self {
self.next_lim_u128_delegate = Box::new(delegate);
self
}
pub fn state(&self) -> &State {
&self.state
}
}
impl Rand for Mock<'_> {
fn next_u64(&mut self) -> u64 {
self.next_u128() as u64
}
fn next_u128(&mut self) -> u128 {
let next_u64_delegate = &mut self.next_u128_delegate;
let r = next_u64_delegate(&self.state);
self.state.next_u128_invocations += 1;
r
}
fn next_bool(&mut self, p: Probability) -> bool {
let surrogate = Surrogate {
next_u128_delegate: &mut self.next_u128_delegate,
state: &mut self.state,
};
let next_bool_delegate = &mut self.next_bool_delegate;
let r = next_bool_delegate(surrogate, p);
self.state.next_bool_invocations += 1;
r
}
fn next_lim_u16(&mut self, lim: u16) -> u16 {
self.next_lim_u128(u128::from(lim)) as u16
}
fn next_lim_u32(&mut self, lim: u32) -> u32 {
self.next_lim_u128(u128::from(lim)) as u32
}
fn next_lim_u64(&mut self, lim: u64) -> u64 {
self.next_lim_u128(u128::from(lim)) as u64
}
fn next_lim_u128(&mut self, lim: u128) -> u128 {
let surrogate = Surrogate {
next_u128_delegate: &mut self.next_u128_delegate,
state: &mut self.state,
};
let next_lim_delegate = &mut self.next_lim_u128_delegate;
let r = next_lim_delegate(surrogate, lim);
self.state.next_lim_u128_invocations += 1;
r
}
}
pub fn counter(range: Range<u128>) -> impl FnMut(&State) -> u128 {
let mut current = range.start;
move |_| {
let c = current;
let next = current + 1;
current = if next == range.end { range.start } else { next };
c
}
}
pub fn fixed(val: u128) -> impl FnMut(&State) -> u128 {
move |_| val
}
pub fn echo(cell: &RefCell<u128>) -> impl FnMut(&State) -> u128 + '_ {
move |_| *cell.borrow()
}
#[cfg(test)]
mod tests;