use crate::prelude::*;
#[derive(Debug)]
pub struct FuncStore<I, O, F>
where
O: 'static,
F: 'static,
{
pub called: Store<Vec<O>>,
pub func: Store<F>,
pub _phantom: std::marker::PhantomData<I>,
}
impl<I, O, F> Copy for FuncStore<I, O, F>
where
O: 'static,
F: 'static,
{
}
impl<I, O, F> Clone for FuncStore<I, O, F>
where
O: 'static,
F: 'static,
{
fn clone(&self) -> Self {
Self {
called: self.called.clone(),
func: self.func.clone(),
_phantom: std::marker::PhantomData,
}
}
}
impl<I, O, F> FuncStore<I, O, F>
where
O: 'static + Send,
F: 'static + Send + Fn(I) -> O,
{
pub fn new(func: F) -> Self {
Self {
called: Store::default(),
func: Store::new(func),
_phantom: std::marker::PhantomData,
}
}
pub fn call(&self, input: I) {
let output = self.func.with(|func| func(input));
self.called.push(output);
}
}
impl<I, O, F> FuncStore<I, O, F>
where
I: Default,
O: 'static + Send,
F: Send + Fn(I) -> O,
{
pub fn call0(&self) {
let output = self.func.with(|func| func(Default::default()));
self.called.push(output);
}
}
impl<I, O, F> FuncStore<I, O, F>
where
O: 'static + Send + Clone,
F: Send + Fn(I) -> O,
{
pub fn call_and_get(&self, input: I) -> O {
let output = self.func.with(|func| func(input));
self.called.push(output.clone());
output
}
}
#[cfg(feature = "nightly")]
impl<I, O, F> FnOnce<(I,)> for FuncStore<I, O, F>
where
O: Send,
F: Send + Fn(I) -> O,
{
type Output = ();
extern "rust-call" fn call_once(self, args: (I,)) -> () {
FuncStore::call(&self, args.0);
}
}
#[cfg(feature = "nightly")]
impl<I, O, F> FnMut<(I,)> for FuncStore<I, O, F>
where
O: Send,
F: Send + Fn(I) -> O,
{
extern "rust-call" fn call_mut(&mut self, args: (I,)) -> () {
FuncStore::call(self, args.0);
}
}
#[cfg(feature = "nightly")]
impl<I, O, F> Fn<(I,)> for FuncStore<I, O, F>
where
O: Send,
F: Send + Fn(I) -> O,
{
extern "rust-call" fn call(&self, args: (I,)) -> () {
FuncStore::call(self, args.0);
}
}
#[cfg(test)]
mod test {
use crate::prelude::*;
#[test]
fn calls_and_records() {
let func_store = FuncStore::new(|n: u32| n + 1);
func_store.call(1);
func_store.call(2);
func_store.called.len().xpect_eq(2);
let outputs = func_store.called.get();
outputs.xpect_eq(vec![2, 3]);
}
#[test]
fn multiple_calls() {
let func_store = FuncStore::new(|v| v);
func_store.call(4);
func_store.call(5);
let outputs = func_store.called.get();
outputs.xpect_eq(vec![4, 5]);
}
#[test]
fn call0_uses_default_input() {
let func_store = FuncStore::new(|n: u32| n + 5);
func_store.call0();
let outputs = func_store.called.get();
outputs.xpect_eq(vec![5]);
}
#[test]
fn call_and_get_returns_and_records() {
let func_store = FuncStore::new(|n: u32| n * 2);
let first = func_store.call_and_get(3);
let second = func_store.call_and_get(4);
first.xpect_eq(6);
second.xpect_eq(8);
let outputs = func_store.called.get();
outputs.xpect_eq(vec![6, 8]);
}
}