1use std::sync::{
2 atomic::{AtomicUsize, Ordering},
3 Arc,
4};
5
6type MockFn<RETURN, ARGS> = dyn Fn(ARGS) -> RETURN + Send + Sync;
7
8pub struct Mock<RETURN, ARGS = ()> {
14 idx: Arc<AtomicUsize>,
15 kind: MockKind<RETURN, ARGS>,
16}
17
18impl<RETURN, ARGS> Mock<RETURN, ARGS> {
19 pub fn always_with_args<F: Fn(usize, ARGS) -> RETURN + Send + Sync + 'static>(f: F) -> Self {
21 Self {
22 idx: Arc::new(AtomicUsize::new(0)),
23 kind: MockKind::Always(Arc::new(Box::new(f))),
24 }
25 }
26
27 pub fn never() -> Self {
29 Self::with(vec![])
30 }
31
32 pub fn once_with_args<F: Fn(ARGS) -> RETURN + Send + Sync + 'static>(f: F) -> Self {
34 Self::with(vec![Box::new(f)])
35 }
36
37 pub fn with(f: Vec<Box<dyn Fn(ARGS) -> RETURN + Send + Sync>>) -> Self {
39 Self {
40 idx: Arc::new(AtomicUsize::new(0)),
41 kind: MockKind::CallSpecific(Arc::new(f)),
42 }
43 }
44
45 pub fn call_with_args(&self, args: ARGS) -> RETURN {
50 let idx = self.idx.fetch_add(1, Ordering::Relaxed);
51 match &self.kind {
52 MockKind::Always(f) => f(idx, args),
53 MockKind::CallSpecific(fns) => {
54 if idx >= fns.len() {
55 panic!("Mock called when it should not have been");
56 }
57 fns[idx](args)
58 }
59 }
60 }
61
62 pub fn count(&self) -> usize {
64 self.idx.load(Ordering::Relaxed)
65 }
66
67 pub fn times(&self) -> usize {
71 match &self.kind {
72 MockKind::Always(_) => usize::MAX,
73 MockKind::CallSpecific(fns) => fns.len(),
74 }
75 }
76}
77
78impl<RETURN> Mock<RETURN, ()> {
79 pub fn always<F: Fn(usize) -> RETURN + Send + Sync + 'static>(f: F) -> Self {
81 Self::always_with_args(move |idx, _| f(idx))
82 }
83
84 pub fn once<F: Fn() -> RETURN + Send + Sync + 'static>(f: F) -> Self {
86 Self::once_with_args(move |_| f())
87 }
88
89 pub fn call(&self) -> RETURN {
94 self.call_with_args(())
95 }
96}
97
98impl<RETURN, ARGS> Clone for Mock<RETURN, ARGS> {
99 fn clone(&self) -> Self {
100 Self {
101 idx: self.idx.clone(),
102 kind: self.kind.clone(),
103 }
104 }
105}
106
107impl<RETURN, ARGS> Default for Mock<RETURN, ARGS> {
108 fn default() -> Self {
109 Self::never()
110 }
111}
112
113enum MockKind<RETURN, ARGS> {
116 Always(Arc<Box<dyn Fn(usize, ARGS) -> RETURN + Send + Sync>>),
117 CallSpecific(Arc<Vec<Box<MockFn<RETURN, ARGS>>>>),
118}
119
120impl<RETURN, ARGS> Clone for MockKind<RETURN, ARGS> {
121 fn clone(&self) -> Self {
122 match self {
123 MockKind::Always(f) => MockKind::Always(f.clone()),
124 MockKind::CallSpecific(fns) => MockKind::CallSpecific(fns.clone()),
125 }
126 }
127}