1#[rustfmt::skip]
2macro_rules! all_the_tuples {
3 ($name:ident) => {
4 $name!([], T1);
5 $name!([T1], T2);
6 $name!([T1, T2], T3);
7 $name!([T1, T2, T3], T4);
8 $name!([T1, T2, T3, T4], T5);
9 $name!([T1, T2, T3, T4, T5], T6);
10 $name!([T1, T2, T3, T4, T5, T6], T7);
11 $name!([T1, T2, T3, T4, T5, T6, T7], T8);
12 $name!([T1, T2, T3, T4, T5, T6, T7, T8], T9);
13 $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9], T10);
14 $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], T11);
15 $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11], T12);
16 $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12], T13);
17 $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13], T14);
18 $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14], T15);
19 $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15], T16);
20 };
21}
22
23#[macro_export]
41macro_rules! named_parameters {
42 ( $vis:vis $param_name:ident { $($key:ident = $value:ty),* $(,)? }) => {
43 #[derive(Debug, Clone)]
44 $vis struct $param_name {
45 $($key: $value),*
46 }
47
48 impl<H> $crate::argument::ParseArguments<H> for $param_name {
49 fn parse(_: &$crate::TestDsl<H>, node: &$crate::kdl::KdlNode) -> Result<Self, $crate::error::TestErrorCase> {
50 $(
51 let $key: $value = $crate::argument::VerbArgument::from_value(node.entry(stringify!($key)).unwrap()).unwrap();
52 )*
53
54 Ok($param_name {
55 $(
56 $key
57 ),*
58 })
59 }
60 }
61 };
62}
63
64#[macro_export]
65#[cfg(not(doc))]
66#[expect(missing_docs, reason = "This is documented further below")]
67macro_rules! named_parameters_verb {
68 (@define_args $struct_name:ident => { |$_name:ident : $_ty:ty $(, $name:ident : $kind:ty)* $(,)?| $rest:block }) => {
69 #[derive(Debug, Clone)]
70 struct $struct_name {
71 $($name : $kind),*
72 }
73 };
74
75 (@get_args $struct_name:ident => |$_name:ident : $_ty:ty $(, $name:ident : $kind:ty)* $(,)?| $rest:block) => {
76 $struct_name {
77 $($name),*
78 }
79 };
80
81 (@parse_args $node:ident => |$_name:ident : $_ty:ty $(, $name:ident : $kind:ty)* $(,)?| $rest:block) => {
82 $(
83 let $name: $kind = $crate::argument::VerbArgument::from_value($node.entry(stringify!($name)).unwrap()).unwrap();
84 )*
85 };
86
87 (@extract $node:ident => |$_name:ident : $_ty:ty $(, $name:ident : $kind:ty)* $(,)?| $rest:block) => {
88 $(
89 let $name: $kind = $node.$name.clone();
90 )*
91 };
92
93 (@verb_params $verb:ident $harness:ident => |$_name:ident : $_ty:ty $(, $name:ident : $kind:ty)* $(,)?| $rest:block) => {
94 $verb($harness, $($name),*)
95 };
96
97 (@call $struct_name:ident => { $($rest:tt)* } => { |$_name:ident : &mut $ty:ty $(,$_:ident : $__:ty)*| $_rest:block }) => {{
98 #[derive(Clone)]
99 struct __Caller;
100
101 impl $crate::verb::CallableVerb<$ty, $struct_name> for __Caller {
102 fn call(&self, harness: &mut $ty, node: &$struct_name) -> $crate::miette::Result<()> {
103
104 let verb = $($rest)*;
105
106 $crate::named_parameters_verb!(@extract node => $($rest)*);
107
108 $crate::named_parameters_verb!(@verb_params verb harness => $($rest)*)
109 }
110 }
111
112 __Caller
113 }};
114
115 ($($input:tt)*) => {{
116 let verb = $crate::verb::FunctionVerb::<_, __NamedVerb>::new(
117 $crate::named_parameters_verb!(@call __NamedVerb => { $($input)* } => { $($input)* })
118 );
119
120 $crate::named_parameters_verb!(@define_args __NamedVerb => { $($input)* });
121
122 impl<H> $crate::argument::ParseArguments<H> for __NamedVerb {
123 fn parse(_: &$crate::TestDsl<H>, node: &$crate::kdl::KdlNode) -> Result<Self, $crate::error::TestErrorCase> {
124
125 $crate::named_parameters_verb!(@parse_args node => $($input)*);
126
127 Ok($crate::named_parameters_verb!(@get_args __NamedVerb => $($input)*))
128 }
129 }
130
131 verb
132 }};
133}
134
135#[cfg(doc)]
150#[macro_export]
151macro_rules! named_parameters_verb {
152 ($($input:tt)*) => {};
153}
154
155#[cfg(test)]
156mod tests {
157 use crate::TestDsl;
158 use crate::argument::ParseArguments;
159
160 #[test]
161 fn simple_kv() {
162 named_parameters!(CoolIntegers {
163 pi = usize,
164 name = String
165 });
166
167 let dsl = TestDsl::<()>::new();
168
169 let node = kdl::KdlNode::parse("foo pi=4 name=PI { other stuff }").unwrap();
170
171 let ints = CoolIntegers::parse(&dsl, &node).unwrap();
172
173 assert_eq!(ints.pi, 4);
174 assert_eq!(ints.name, "PI");
175 }
176
177 #[test]
178 fn simple_named_closure() {
179 let mut dsl = TestDsl::<()>::new();
180
181 dsl.add_verb(
182 "test",
183 named_parameters_verb!(|_harness: &mut (), name: String, pi: usize| {
184 println!("{name} = {pi}");
185 Ok(())
186 }),
187 );
188 }
189}