test_dsl/
argument.rs

1//! Traits related to arguments of verbs and conditions
2
3use crate::ConditionInstance;
4use crate::TestDsl;
5use crate::VerbInstance;
6use crate::error;
7use crate::error::TestErrorCase;
8
9/// Types that can be parsed from a node as arguments
10///
11/// This includes both named/positional parameters as well as child nodes
12pub trait ParseArguments<H>: std::fmt::Debug + Clone + Sized + 'static {
13    /// Do the parsing and return an instance
14    ///
15    /// See [`VerbInstance`] and
16    /// [`ConditionInstance`] for how to get an instance from a node.
17    fn parse(test_dsl: &TestDsl<H>, node: &kdl::KdlNode) -> Result<Self, TestErrorCase>;
18}
19
20pub(crate) trait BoxedArguments<H>: std::fmt::Debug + std::any::Any {
21    fn clone_box(&self) -> Box<dyn BoxedArguments<H>>;
22    fn as_dyn_any(&self) -> &dyn std::any::Any;
23}
24
25impl<H: 'static> Clone for Box<dyn BoxedArguments<H>> {
26    fn clone(&self) -> Self {
27        (**self).clone_box()
28    }
29}
30
31impl<H, A: ParseArguments<H>> BoxedArguments<H> for A {
32    fn clone_box(&self) -> Box<dyn BoxedArguments<H>> {
33        Box::new(self.clone())
34    }
35
36    fn as_dyn_any(&self) -> &dyn std::any::Any {
37        self
38    }
39}
40
41impl<H> ParseArguments<H> for ((),) {
42    fn parse(_test_dsl: &TestDsl<H>, _node: &kdl::KdlNode) -> Result<Self, TestErrorCase> {
43        Ok(((),))
44    }
45}
46
47macro_rules! impl_parse_arguments {
48    (
49        [$($ty:ident),*], $last:ident
50    ) => {
51        #[allow(non_snake_case, unused_mut)]
52        impl<H, $($ty,)* $last> ParseArguments<H> for ($($ty,)* $last,)
53            where
54                $( $ty: VerbArgument + 'static , )*
55                $last: VerbArgument + 'static,
56                ($($ty,)* $last,): std::fmt::Debug,
57        {
58            fn parse(_test_dsl: &TestDsl<H>, node: &kdl::KdlNode) -> Result<Self, TestErrorCase> {
59                let mut args = node.iter();
60
61                let total_count = 1
62                    $(
63                        + {
64                            const _: () = {
65                                #[allow(unused)]
66                                let $ty = ();
67                            };
68                            1
69                        }
70
71                    )*;
72
73                let mut running_count = 1;
74
75                $(
76                    let arg = args.next().ok_or_else(|| TestErrorCase::MissingArgument {
77                        parent: node.span(),
78                        missing: format!("This verb takes {} arguments, you're missing the {}th argument.", total_count, running_count),
79                    })?;
80
81                    let $ty = <$ty as VerbArgument>::from_value(arg).ok_or_else(|| {
82                        TestErrorCase::WrongArgumentType {
83                            parent: node.name().span(),
84                            argument: arg.span(),
85                            expected: format!("This verb takes a '{}' as its argument here.", <$ty as VerbArgument>::get_error_type_name()),
86                        }
87                    })?;
88                    running_count += 1;
89                )*
90
91                let _ = running_count;
92
93                let arg = args.next().ok_or_else(|| TestErrorCase::MissingArgument {
94                    parent: node.span(),
95                    missing: format!("This verb takes {tc} arguments, you're missing the {tc}th argument.", tc = total_count),
96                })?;
97                let $last = <$last as VerbArgument>::from_value(arg).ok_or_else(|| {
98                    TestErrorCase::WrongArgumentType {
99                        parent: node.name().span(),
100                        argument: arg.span(),
101                        expected: format!("This verb takes a '{}' as its argument here.", <$last as VerbArgument>::get_error_type_name()),
102                    }
103                })?;
104
105
106                Ok(($($ty,)* $last,))
107            }
108        }
109    };
110}
111
112all_the_tuples!(impl_parse_arguments);
113
114/// A type that can be used as an argument of Verbs and Conditions
115pub trait VerbArgument: Clone {
116    /// A human-readable typename
117    ///
118    /// This is shown only in error-messages
119    fn get_error_type_name() -> &'static str {
120        std::any::type_name::<Self>()
121    }
122
123    /// Convert from a [`KdlEntry`](kdl::KdlEntry) to the value
124    ///
125    /// Implementations are free to accept more than a single way of interpreting values. E.g. a
126    /// string and a integer.
127    fn from_value(value: &kdl::KdlEntry) -> Option<Self>;
128}
129
130impl VerbArgument for String {
131    fn from_value(value: &kdl::KdlEntry) -> Option<Self> {
132        value.value().as_string().map(ToOwned::to_owned)
133    }
134}
135
136impl VerbArgument for usize {
137    fn from_value(value: &kdl::KdlEntry) -> Option<Self> {
138        value.value().as_integer().map(|i| i as usize)
139    }
140}
141
142impl VerbArgument for f64 {
143    fn from_value(value: &kdl::KdlEntry) -> Option<Self> {
144        value.value().as_float()
145    }
146}
147
148impl VerbArgument for bool {
149    fn from_value(value: &kdl::KdlEntry) -> Option<Self> {
150        value.value().as_bool()
151    }
152}
153
154/// Parameters with a list of nodes that are conditions
155pub struct ConditionChildren<H, A> {
156    parameters: A,
157    children: Vec<ConditionInstance<H>>,
158}
159
160impl<H, A: std::fmt::Debug> std::fmt::Debug for ConditionChildren<H, A> {
161    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
162        f.debug_struct("ConditionChildren")
163            .field("parameters", &self.parameters)
164            .field("children", &self.children)
165            .finish()
166    }
167}
168
169impl<H: 'static, A: Clone> Clone for ConditionChildren<H, A> {
170    fn clone(&self) -> Self {
171        Self {
172            parameters: self.parameters.clone(),
173            children: self.children.clone(),
174        }
175    }
176}
177
178impl<H, A> ConditionChildren<H, A> {
179    /// Get the parameters
180    pub fn parameters(&self) -> &A {
181        &self.parameters
182    }
183
184    /// Get the children nodes
185    pub fn children(&self) -> &[ConditionInstance<H>] {
186        &self.children
187    }
188}
189
190impl<H: 'static, A: ParseArguments<H>> ParseArguments<H> for ConditionChildren<H, A> {
191    fn parse(test_dsl: &TestDsl<H>, node: &kdl::KdlNode) -> Result<Self, error::TestErrorCase> {
192        let arguments = A::parse(test_dsl, node)?;
193
194        let children = node
195            .iter_children()
196            .map(|node| ConditionInstance::with_test_dsl(test_dsl, node))
197            .collect::<Result<_, _>>()?;
198
199        Ok(ConditionChildren {
200            parameters: arguments,
201            children,
202        })
203    }
204}
205
206/// Parameters with a list of nodes that are verbs
207pub struct VerbChildren<H, A> {
208    parameters: A,
209    children: Vec<VerbInstance<H>>,
210}
211
212impl<H, A: std::fmt::Debug> std::fmt::Debug for VerbChildren<H, A> {
213    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
214        f.debug_struct("VerbChildren")
215            .field("parameters", &self.parameters)
216            .field("children", &self.children)
217            .finish()
218    }
219}
220
221impl<H: 'static, A: Clone> Clone for VerbChildren<H, A> {
222    fn clone(&self) -> Self {
223        Self {
224            parameters: self.parameters.clone(),
225            children: self.children.clone(),
226        }
227    }
228}
229
230impl<H, A> VerbChildren<H, A> {
231    /// Get the parameters
232    pub fn parameters(&self) -> &A {
233        &self.parameters
234    }
235
236    /// Get the children
237    pub fn children(&self) -> &[VerbInstance<H>] {
238        &self.children
239    }
240}
241
242impl<H: 'static, A: ParseArguments<H>> ParseArguments<H> for VerbChildren<H, A> {
243    fn parse(test_dsl: &TestDsl<H>, node: &kdl::KdlNode) -> Result<Self, error::TestErrorCase> {
244        let arguments = A::parse(test_dsl, node)?;
245
246        let children = node
247            .iter_children()
248            .map(|node| VerbInstance::with_test_dsl(test_dsl, node))
249            .collect::<Result<_, _>>()?;
250
251        Ok(VerbChildren {
252            parameters: arguments,
253            children,
254        })
255    }
256}