1use std::any::Any;
4use std::marker::PhantomData;
5
6use crate::arguments::VerbArgument;
7use crate::error::TestErrorCase;
8
9pub trait TestCondition<H>: 'static {
14 fn check_now(&self, harness: &H, node: &kdl::KdlNode) -> Result<bool, TestErrorCase>;
22
23 fn wait_until(&self, harness: &H, node: &kdl::KdlNode) -> Result<bool, TestErrorCase>;
31
32 fn clone_box(&self) -> Box<dyn TestCondition<H>>;
34}
35
36impl<H: 'static> Clone for Box<dyn TestCondition<H>> {
37 fn clone(&self) -> Self {
38 let this: &dyn TestCondition<H> = &**self;
39 this.clone_box()
40 }
41}
42
43pub trait Checker<H, T>: Clone + 'static {
49 fn check(&self, harness: &H, node: &kdl::KdlNode) -> Result<bool, TestErrorCase>;
51}
52
53struct BoxedChecker<H> {
54 checker: Box<dyn Any>,
55 check_fn: fn(&dyn Any, harness: &H, node: &kdl::KdlNode) -> Result<bool, TestErrorCase>,
56 clone_fn: fn(&dyn Any) -> Box<dyn Any>,
57}
58
59impl<H> BoxedChecker<H> {
60 fn new<C, T>(checker: C) -> Self
61 where
62 C: Checker<H, T>,
63 {
64 BoxedChecker {
65 checker: Box::new(checker),
66 check_fn: |this, harness, node| {
67 let this: &C = this.downcast_ref().unwrap();
68
69 this.check(harness, node)
70 },
71 clone_fn: |this| {
72 let this: &C = this.downcast_ref().unwrap();
73
74 Box::new(this.clone())
75 },
76 }
77 }
78
79 fn check(&self, harness: &H, node: &kdl::KdlNode) -> Result<bool, TestErrorCase> {
80 (self.check_fn)(&*self.checker, harness, node)
81 }
82}
83
84impl<H> Clone for BoxedChecker<H> {
85 fn clone(&self) -> Self {
86 BoxedChecker {
87 checker: (self.clone_fn)(&*self.checker),
88 check_fn: self.check_fn,
89 clone_fn: self.clone_fn,
90 }
91 }
92}
93
94pub struct Condition<H> {
99 now: Option<BoxedChecker<H>>,
100 wait: Option<BoxedChecker<H>>,
101 _pd: PhantomData<fn(H)>,
102}
103
104impl<H> Condition<H> {
105 pub fn new_now<C, T>(now: C) -> Self
109 where
110 C: Checker<H, T>,
111 {
112 Condition {
113 now: Some(BoxedChecker::new(now)),
114 wait: None,
115 _pd: PhantomData,
116 }
117 }
118}
119
120impl<H> Clone for Condition<H> {
121 fn clone(&self) -> Self {
122 Condition {
123 now: self.now.clone(),
124 wait: self.wait.clone(),
125 _pd: PhantomData,
126 }
127 }
128}
129
130impl<H, F> Checker<H, ((),)> for F
131where
132 F: Fn(&H) -> miette::Result<bool>,
133 F: Clone + 'static,
134{
135 fn check(&self, harness: &H, node: &kdl::KdlNode) -> Result<bool, TestErrorCase> {
136 self(harness).map_err(|error| TestErrorCase::Error {
137 error,
138 label: node.span(),
139 })
140 }
141}
142
143#[rustfmt::skip]
144macro_rules! all_the_tuples {
145 ($name:ident) => {
146 $name!([], T1);
147 $name!([T1], T2);
148 $name!([T1, T2], T3);
149 $name!([T1, T2, T3], T4);
150 $name!([T1, T2, T3, T4], T5);
151 $name!([T1, T2, T3, T4, T5], T6);
152 $name!([T1, T2, T3, T4, T5, T6], T7);
153 $name!([T1, T2, T3, T4, T5, T6, T7], T8);
154 $name!([T1, T2, T3, T4, T5, T6, T7, T8], T9);
155 $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9], T10);
156 $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], T11);
157 $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11], T12);
158 $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12], T13);
159 $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13], T14);
160 $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14], T15);
161 $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15], T16);
162 };
163}
164
165macro_rules! impl_callable {
166 (
167 [$($ty:ident),*], $last:ident
168 ) => {
169 #[allow(non_snake_case, unused_mut)]
170 impl<H, F, $($ty,)* $last> Checker<H, ($($ty,)* $last,)> for F
171 where
172 F: Fn(&H, $($ty,)* $last,) -> miette::Result<bool>,
173 F: Clone + 'static,
174 $( $ty: VerbArgument, )*
175 $last: VerbArgument,
176 {
177 fn check(&self, harness: &H, node: &kdl::KdlNode) -> Result<bool, TestErrorCase> {
178 let mut args = node.iter();
179
180 let total_count = 1
181 $(
182 + {
183 const _: () = {
184 #[allow(unused)]
185 let $ty = ();
186 };
187 1
188 }
189
190 )*;
191
192 let mut running_count = 1;
193
194 $(
195 let arg = args.next().ok_or_else(|| TestErrorCase::MissingArgument {
196 parent: node.span(),
197 missing: format!("This condition takes {} arguments, you're missing the {}th argument.", total_count, running_count),
198 })?;
199
200 let $ty = <$ty as VerbArgument>::from_value(arg).ok_or_else(|| {
201 TestErrorCase::WrongArgumentType {
202 parent: node.name().span(),
203 argument: arg.span(),
204 expected: format!("This condition takes a '{}' as its argument here.", <$ty as VerbArgument>::TYPE_NAME),
205 }
206 })?;
207 running_count += 1;
208 )*
209
210 let _ = running_count;
211
212 let arg = args.next().ok_or_else(|| TestErrorCase::MissingArgument {
213 parent: node.span(),
214 missing: format!("This condition takes {tc} arguments, you're missing the {tc}th argument.", tc = total_count),
215 })?;
216 let $last = <$last as VerbArgument>::from_value(arg).ok_or_else(|| {
217 TestErrorCase::WrongArgumentType {
218 parent: node.name().span(),
219 argument: arg.span(),
220 expected: format!("This condition takes a '{}' as its argument here.", <$last as VerbArgument>::TYPE_NAME),
221 }
222 })?;
223
224 self(harness, $($ty,)* $last,).map_err(|error| TestErrorCase::Error {
225 error,
226 label: node.span()
227 })
228 }
229 }
230 };
231}
232
233all_the_tuples!(impl_callable);
234
235impl<H> TestCondition<H> for Condition<H>
236where
237 H: 'static,
238{
239 fn check_now(&self, harness: &H, node: &kdl::KdlNode) -> Result<bool, TestErrorCase> {
240 let Some(check) = self.now.as_ref().map(|now| now.check(harness, node)) else {
241 return Err(TestErrorCase::Error {
242 error: miette::miette!("Condition does not implement checking now"),
243 label: node.span(),
244 });
245 };
246
247 check
248 }
249
250 fn wait_until(&self, harness: &H, node: &kdl::KdlNode) -> Result<bool, TestErrorCase> {
251 let Some(check) = self.wait.as_ref().map(|wait| wait.check(harness, node)) else {
252 return Err(TestErrorCase::Error {
253 error: miette::miette!("Condition does not implement waiting"),
254 label: node.span(),
255 });
256 };
257
258 check
259 }
260
261 fn clone_box(&self) -> Box<dyn TestCondition<H>> {
262 Box::new(self.clone())
263 }
264}