mod once;
use std::num::NonZeroUsize;
use crate::{
matcher::{AnyInvocation, InvocationMatcher},
mock::{self, stub},
Faux,
};
pub use once::Once;
use stub::Stub;
pub struct When<'m, R, I, O, M: InvocationMatcher<I>> {
id: fn(R, I) -> O,
name: &'static str,
store: &'m mut mock::Store<'static>,
times: Option<stub::Times>,
matcher: M,
}
impl<'m, R, I, O> When<'m, R, I, O, AnyInvocation> {
#[doc(hidden)]
pub fn new(id: fn(R, I) -> O, name: &'static str, faux: &'m mut Faux) -> Self {
let store = faux.unique_store().expect("faux: failed to get unique handle to mock. Adding stubs to a mock instance may only be done prior to cloning the mock.");
When {
id,
name,
store,
matcher: AnyInvocation,
times: Some(stub::Times::Always),
}
}
}
impl<'m, R, I, O, M: InvocationMatcher<I> + Send + 'static> When<'m, R, I, O, M> {
pub fn then_return(self, value: O)
where
O: Send + Clone + 'static,
{
self.then(move |_: I| value.clone());
}
pub fn then(self, stub: impl FnMut(I) -> O + 'static + Send)
where
O: 'static,
{
self.add_stub(Box::new(stub));
}
pub unsafe fn then_unchecked_return(self, value: O)
where
O: Send + Clone,
{
self.then_unchecked(move |_: I| value.clone())
}
pub unsafe fn then_unchecked(self, stub: impl FnMut(I) -> O + Send) {
let stub: Box<dyn FnMut(I) -> O + Send> = Box::new(stub);
let stub: Box<_> = std::mem::transmute(stub);
self.add_stub(stub);
}
pub fn times(mut self, times: usize) -> Self {
self.times = NonZeroUsize::new(times).map(stub::Times::Times);
self
}
pub fn once(self) -> Once<'m, R, I, O, M> {
Once::new(self.id, self.name, self.store, self.matcher)
}
pub fn with_args<N: InvocationMatcher<I> + Send + 'static>(
self,
matcher: N,
) -> When<'m, R, I, O, N> {
When {
matcher,
id: self.id,
name: self.name,
store: self.store,
times: self.times,
}
}
fn add_stub(self, stub: Box<dyn FnMut(I) -> O + Send + 'static>) {
let answer = match self.times {
None => stub::Answer::Exhausted,
Some(times) => stub::Answer::Many { times, stub },
};
self.store
.get_mut(self.id, self.name)
.add_stub(Stub::new(answer, self.matcher));
}
}