1use std::fmt::Debug;
2
3use parking_lot::Mutex;
4
5#[derive(Debug, PartialEq)]
6pub(crate) enum Output<O> {
7 CallsRealImpl,
8 ErrorCalledOnce,
10 Found(O),
11}
12
13pub enum Behavior<I, O> {
15 Function {
17 clone: fn(&I) -> I,
18 call: Box<dyn FnMut(I) -> O + Send + 'static>,
19 },
20 Const(Mutex<Box<dyn Iterator<Item = O> + Send + 'static>>),
22 Once(Mutex<Option<O>>),
24 CallsRealImpl,
26}
27
28impl<I: Debug, O: Debug> std::fmt::Debug for Behavior<I, O> {
29 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
30 match self {
31 Self::Function { .. } => f.debug_tuple("Function(_)").finish(),
32 Self::Const(cons) => f
33 .debug_tuple("Const")
34 .field(&cons.lock().next().unwrap())
35 .finish(),
36 Self::Once(once) => f
37 .debug_tuple("Once")
38 .field(&once.lock().as_ref().unwrap())
39 .finish(),
40 Self::CallsRealImpl => write!(f, "CallsRealImpl"),
41 }
42 }
43}
44
45impl<I, O> Behavior<I, O> {
46 pub(crate) fn called(&mut self, input: &I) -> Output<O> {
47 match self {
48 Behavior::Function { clone, call } => Output::Found(call(clone(input))),
49 Behavior::Const(cons) => Output::Found(cons.get_mut().next().unwrap()),
50 Behavior::Once(once) => {
51 if let Some(ret) = once.lock().take() {
52 Output::Found(ret)
53 } else {
54 Output::ErrorCalledOnce
55 }
56 }
57 Behavior::CallsRealImpl => Output::CallsRealImpl,
58 }
59 }
60}
61
62mry_macros::create_behaviors!();
63
64#[cfg(test)]
65mod tests {
66 use std::iter::repeat;
67
68 use super::*;
69
70 #[test]
71 fn test_assert_send() {
72 fn assert_send<T: Send>() {}
73 assert_send::<Behavior<(), ()>>();
74 }
75
76 #[test]
77 fn function() {
78 assert_eq!(
79 Behavior::Function {
80 call: Box::new(|()| "aaa"),
81 clone: Clone::clone
82 }
83 .called(&()),
84 Output::Found("aaa")
85 );
86 }
87
88 #[test]
89 fn const_value() {
90 assert_eq!(
91 Behavior::Const(Mutex::new(Box::new(repeat("aaa")))).called(&()),
92 Output::Found("aaa")
93 );
94 }
95
96 #[test]
97 fn calls_real_impl() {
98 assert_eq!(
99 Behavior::<_, ()>::CallsRealImpl.called(&()),
100 Output::CallsRealImpl
101 );
102 }
103
104 #[test]
105 fn debug_calls_real_impl() {
106 assert_eq!(
107 format!("{:?}", Behavior::<u8, u8>::CallsRealImpl),
108 "CallsRealImpl".to_string()
109 )
110 }
111
112 #[test]
113 fn debug_const() {
114 assert_eq!(
115 format!(
116 "{:?}",
117 Behavior::<u8, u8>::Const(Mutex::new(Box::new(repeat(3))))
118 ),
119 "Const(3)".to_string()
120 )
121 }
122
123 #[test]
124 fn debug_function() {
125 assert_eq!(
126 format!(
127 "{:?}",
128 Behavior::<u8, u8>::Function {
129 clone: Clone::clone,
130 call: Box::new(|a| a)
131 }
132 ),
133 "Function(_)".to_string()
134 )
135 }
136}