test_dsl/
verb.rs

1//! Definition of verbs
2//!
3//! Verbs are the bread and butter of `test-dsl`. They define the behaviour that is then run
4//! against your test harness.
5
6use std::any::Any;
7use std::marker::PhantomData;
8
9use crate::BoxedArguments;
10use crate::TestDsl;
11use crate::argument::ParseArguments;
12use crate::argument::VerbArgument;
13use crate::error::TestErrorCase;
14
15/// A verb is anything that 'does' things in a [`TestCase`](crate::test_case::TestCase)
16pub trait Verb<H>: std::fmt::Debug + Clone + 'static {
17    /// Arguments to this verb
18    type Arguments: ParseArguments<H>;
19
20    /// Run the verb, and do its thing
21    fn run(&self, harness: &mut H, arguments: &Self::Arguments) -> miette::Result<()>;
22}
23
24pub(crate) struct ErasedVerb<H> {
25    verb: Box<dyn Any>,
26    fn_parse_args:
27        fn(&crate::TestDsl<H>, &kdl::KdlNode) -> Result<Box<dyn BoxedArguments<H>>, TestErrorCase>,
28    fn_run: fn(&dyn Any, &mut H, &dyn Any) -> miette::Result<()>,
29    fn_clone: fn(&dyn Any) -> Box<dyn Any>,
30}
31
32impl<H> std::fmt::Debug for ErasedVerb<H> {
33    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
34        f.debug_struct("ErasedVerb")
35            .field("verb", &self.verb)
36            .field("fn_parse_args", &self.fn_parse_args)
37            .field("fn_run", &self.fn_run)
38            .field("fn_clone", &self.fn_clone)
39            .finish()
40    }
41}
42
43impl<H> Clone for ErasedVerb<H> {
44    fn clone(&self) -> Self {
45        Self {
46            verb: (self.fn_clone)(&*self.verb),
47            fn_parse_args: self.fn_parse_args,
48            fn_run: self.fn_run,
49            fn_clone: self.fn_clone,
50        }
51    }
52}
53
54impl<H> ErasedVerb<H> {
55    pub(crate) fn erase<V>(verb: V) -> Self
56    where
57        V: Verb<H>,
58    {
59        ErasedVerb {
60            verb: Box::new(verb),
61            fn_parse_args: |test_dsl, node| {
62                <V::Arguments as ParseArguments<H>>::parse(test_dsl, node).map(|a| {
63                    let args = Box::new(a);
64                    args as _
65                })
66            },
67            fn_run: |this, harness, arguments| {
68                let this: &V = this.downcast_ref().unwrap();
69                let arguments: &V::Arguments = arguments.downcast_ref().unwrap();
70
71                this.run(harness, arguments)
72            },
73            fn_clone: |this| {
74                let this: &V = this.downcast_ref().unwrap();
75
76                Box::new(this.clone())
77            },
78        }
79    }
80
81    pub(crate) fn parse_args(
82        &self,
83        test_dsl: &TestDsl<H>,
84        node: &kdl::KdlNode,
85    ) -> Result<Box<dyn BoxedArguments<H>>, TestErrorCase> {
86        (self.fn_parse_args)(test_dsl, node)
87    }
88
89    pub(crate) fn run(&self, harness: &mut H, arguments: &dyn Any) -> miette::Result<()> {
90        (self.fn_run)(&*self.verb, harness, arguments)
91    }
92}
93
94/// A verb defined through a closure/function
95///
96/// See the [`CallableVerb`] trait for what can be used
97pub struct FunctionVerb<H, T> {
98    func: BoxedCallable<H, T>,
99    _pd: PhantomData<fn(H, T)>,
100}
101
102impl<H, T> std::fmt::Debug for FunctionVerb<H, T> {
103    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
104        f.debug_struct("FunctionVerb")
105            .field("func", &self.func)
106            .field("_pd", &self._pd)
107            .finish()
108    }
109}
110
111impl<H, T> Clone for FunctionVerb<H, T> {
112    fn clone(&self) -> Self {
113        Self {
114            func: self.func.clone(),
115            _pd: self._pd,
116        }
117    }
118}
119
120impl<H, T> FunctionVerb<H, T> {
121    /// Create a new verb using a closure/function
122    pub fn new<F>(func: F) -> Self
123    where
124        F: CallableVerb<H, T>,
125    {
126        FunctionVerb {
127            func: BoxedCallable::new(func),
128            _pd: PhantomData,
129        }
130    }
131}
132
133struct BoxedCallable<H, T> {
134    callable: Box<dyn Any>,
135    call_fn: fn(&dyn Any, &mut H, &T) -> miette::Result<()>,
136    clone_fn: fn(&dyn Any) -> Box<dyn Any>,
137}
138
139impl<H, T> std::fmt::Debug for BoxedCallable<H, T> {
140    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
141        f.debug_struct("BoxedCallable")
142            .field("callable", &self.callable)
143            .field("call_fn", &self.call_fn)
144            .field("clone_fn", &self.clone_fn)
145            .finish()
146    }
147}
148
149impl<H, T> Clone for BoxedCallable<H, T> {
150    fn clone(&self) -> Self {
151        BoxedCallable {
152            callable: (self.clone_fn)(&*self.callable),
153            call_fn: self.call_fn,
154            clone_fn: self.clone_fn,
155        }
156    }
157}
158
159impl<H, T> BoxedCallable<H, T> {
160    fn new<F>(callable: F) -> Self
161    where
162        F: CallableVerb<H, T>,
163    {
164        BoxedCallable {
165            callable: Box::new(callable),
166            call_fn: |this, harness, node| {
167                let this: &F = this.downcast_ref().unwrap();
168                this.call(harness, node)
169            },
170            clone_fn: |this| {
171                let this: &F = this.downcast_ref().unwrap();
172                Box::new(this.clone())
173            },
174        }
175    }
176
177    fn call(&self, harness: &mut H, args: &T) -> miette::Result<()> {
178        (self.call_fn)(&*self.callable, harness, args)
179    }
180}
181
182/// Closure/functions that can be used as a Verb
183///
184/// This trait is implemented for closures with up to 16 arguments. They all have to be [`VerbArgument`]s.
185pub trait CallableVerb<H, T>: Clone + 'static {
186    /// Call the underlying closure
187    fn call(&self, harness: &mut H, node: &T) -> miette::Result<()>;
188}
189
190impl<H, F, A> CallableVerb<H, ((), A)> for F
191where
192    F: Fn(&mut H, ((), A)) -> miette::Result<()>,
193    F: Clone + 'static,
194    A: ParseArguments<H>,
195{
196    fn call(&self, harness: &mut H, node: &((), A)) -> miette::Result<()> {
197        self(harness, node.clone())
198    }
199}
200
201impl<H, F> CallableVerb<H, ((),)> for F
202where
203    F: Fn(&mut H) -> miette::Result<()>,
204    F: Clone + 'static,
205{
206    fn call(&self, harness: &mut H, _node: &((),)) -> miette::Result<()> {
207        self(harness)
208    }
209}
210
211macro_rules! impl_callable {
212    (
213        [$($ty:ident),*], $last:ident
214    ) => {
215        #[allow(non_snake_case, unused_mut)]
216        impl<H, F, $($ty,)* $last> CallableVerb<H, ($($ty,)* $last,)> for F
217            where
218                F: Fn(&mut H, $($ty,)* $last,) -> miette::Result<()>,
219                F: Clone + 'static,
220                $( $ty: VerbArgument, )*
221                $last: VerbArgument,
222        {
223            fn call(&self, harness: &mut H, arguments: &($($ty,)* $last,)) -> miette::Result<()> {
224                let ($($ty,)* $last,) = arguments.clone();
225                self(harness, $($ty,)* $last,)
226            }
227        }
228    };
229}
230
231all_the_tuples!(impl_callable);
232
233impl<T, H: 'static> Verb<H> for FunctionVerb<H, T>
234where
235    T: ParseArguments<H>,
236{
237    type Arguments = T;
238    fn run(&self, harness: &mut H, args: &T) -> miette::Result<()> {
239        self.func.call(harness, args)
240    }
241}