1#[cfg(feature = "async")]
2use crate::config::BuilderGenerator;
3use crate::{
4 context::{Resource, ResourceId},
5 error::TestError,
6};
7#[cfg(feature = "async")]
8use core::future::Future;
9#[cfg(feature = "async")]
10use core::panic::AssertUnwindSafe;
11use core::panic::{RefUnwindSafe, UnwindSafe};
12#[cfg(feature = "async")] use paste::paste;
13use std::result::Result;
14
15pub struct HandlerParams {
16 #[cfg(feature = "async")]
17 pub(crate) runtime_builder: BuilderGenerator,
18}
19
20pub enum HandlerError {
21 NotInContext(ResourceId),
22 Panic(Box<dyn core::any::Any + Send>),
23}
24
25type TestResult = Result<(), Box<dyn TestError>>;
28pub type HandlerResult = Result<TestResult, HandlerError>;
29
30pub trait Handler<R, I, O, C, const ASYNC: bool> {
31 fn call(&mut self, context: C, params: &HandlerParams) -> HandlerResult;
32
33 fn get_resource_ids(&self) -> (Vec<ResourceId>, Vec<ResourceId>, Vec<ResourceId>);
35}
36
37macro_rules! int_implement_get_resource {
38 ( $( $r:ident ),* ,0, $( $i:ident ),* ,1, $( $o:ident ),* ) => {
39 #[allow(unused_mut)]
40 fn get_resource_ids(&self) -> (Vec<ResourceId>, Vec<ResourceId>, Vec<ResourceId>) {
41 let reference = vec![$($r::get_resource_id()),*];
42 let inputs = vec![$($i::get_resource_id()),*];
43 let outputs = vec![$($o::get_resource_id()),*];
44 (reference, inputs, outputs)
45 }
46 }
47}
48
49macro_rules! implement_handler {
50 ( $( $r:ident ),* ,0, $( $i:ident ),* ,1, $( $o:ident ),* ) => {
51 #[allow(non_snake_case, unused_parens)]
52 impl<F,$($r,)* $($i,)* $($o,)* C, E> Handler<($($r,)*), ($($i,)*), ($($o,)*), C, false> for F
53 where
54 F: Fn($(& $r,)* $($i),* ) -> Result<($($o),*) , E>,
55 F: RefUnwindSafe,
56 $(
57 $r: Resource<Context = C> + UnwindSafe,
58 $r: RefUnwindSafe,
59 )*
60 $(
61 $i: Resource<Context = C> + UnwindSafe,
62 )*
63 $(
64 $o: Resource<Context = C>,
65 )*
66 E: TestError + 'static,
67 {
68 fn call(&mut self, #[allow(unused_variables)] context: C, _params: &HandlerParams) -> HandlerResult {
69 $(
70 let $r = $r::from_context(&context).ok_or(HandlerError::NotInContext($r::get_resource_id()))?;
71 )*
72 $(
73 let $i = $i::from_context(&context).ok_or(HandlerError::NotInContext($i::get_resource_id()))?;
74 )*
75 let result = std::panic::catch_unwind(|| (self)($(& $r,)* $($i),*));
76 $(
77 $r::into_context(&context, $r);
78 )*
79 match result {
80 Ok(Ok(($($o),*))) => {
81 $(
82 $o::into_context(&context, $o);
83 )*
84 Ok(Ok(()))
85 }
86 Ok(Err(e)) => Ok(Err(Box::new(e))),
87 Err(panic_e) => {
88 Err(HandlerError::Panic(panic_e))
89 },
90 }
91 }
92
93 int_implement_get_resource!($($r),* ,0, $($i),* ,1, $($o),*);
94 }
95
96 #[cfg(feature = "async")]
97 paste!{
98
99 trait [<AsyncBorrowFn $($r)* $($i)* $($o)*>]<'a, $($r: ?Sized + 'a,)* $($i),*>: Fn($(&'a $r,)* $($i),*) -> Self::Fut {
102 type Out;
103 type Fut: Future<Output = Self::Out> + 'a;
104 }
105
106 impl<'a, $($r,)* $($i,)* F, Fut> [<AsyncBorrowFn $($r)* $($i)* $($o)*>]<'a, $($r,)* $($i),*> for F
107 where
108 $(
109 $r: ?Sized + 'a,
110 )*
111 F: Fn($(&'a $r,)* $($i),*) -> Fut,
112 Fut: Future + 'a,
113 {
114 type Out = Fut::Output;
115 type Fut = Fut;
116 }
117
118 #[allow(non_snake_case, unused_parens)]
119 impl<F,$($r,)* $($i,)* $($o,)* C, E> Handler<($($r,)*), ($($i,)*), ($($o,)*), C, true> for F
120 where
121 F: for<'a> [<AsyncBorrowFn $($r)* $($i)* $($o)*>] <'a, $($r,)* $($i,)* Out = Result<($($o),*), E>>,
122 F: RefUnwindSafe,
123 $(
124 $r: Resource<Context = C> + UnwindSafe,
125 $r: RefUnwindSafe,
126 )*
127 $(
128 $i: Resource<Context = C> + UnwindSafe,
129 )*
130 $(
131 $o: Resource<Context = C>,
132 )*
133 E: TestError + 'static,
134 {
135 fn call(&mut self, #[allow(unused_variables)] context: C, params: &HandlerParams) -> HandlerResult {
136 $(
137 let $r = $r::from_context(&context).ok_or(HandlerError::NotInContext($r::get_resource_id()))?;
138 let [<ref_ $r>] = & $r;
139 )*
140 $(
141 let $i = $i::from_context(&context).ok_or(HandlerError::NotInContext($i::get_resource_id()))?;
142 )*
143 use futures_util::future::FutureExt;
144 let rt = (params.runtime_builder)().build().unwrap();
145 let fut = (self)($([<ref_ $r>],)* $($i),*);
146 let result = rt.block_on(AssertUnwindSafe(fut).catch_unwind());
147 $(
148 $r::into_context(&context, $r);
149 )*
150 match result {
151 Ok(Ok(($($o),*))) => {
152 $(
153 $o::into_context(&context, $o);
154 )*
155 Ok(Ok(()))
156 }
157 Ok(Err(e)) => Ok(Err(Box::new(e))),
158 Err(panic_e) => {
159 Err(HandlerError::Panic(panic_e))
160 },
161 }
162 }
163
164 int_implement_get_resource!($($r),* ,0, $($i),* ,1, $($o),*);
165 }
166 }
167
168 };
169}
170
171implement_handler!(, 0,, 1,);
174implement_handler!(, 0,, 1, O1);
175implement_handler!(, 0,, 1, O1, O2);
176implement_handler!(, 0,, 1, O1, O2, O3);
177implement_handler!(, 0, I1, 1,);
178implement_handler!(, 0, I1, 1, O1);
179implement_handler!(, 0, I1, 1, O1, O2);
180implement_handler!(, 0, I1, 1, O1, O2, O3);
181implement_handler!(, 0, I1, 1, O1, O2, O3, O4);
182implement_handler!(, 0, I1, I2, 1,);
183implement_handler!(, 0, I1, I2, 1, O1);
184implement_handler!(, 0, I1, I2, 1, O1, O2);
185implement_handler!(, 0, I1, I2, 1, O1, O2, O3);
186implement_handler!(, 0, I1, I2, 1, O1, O2, O3, O4);
187implement_handler!(, 0, I1, I2, 1, O1, O2, O3, O4, O5);
188implement_handler!(, 0, I1, I2, I3, 1,);
189implement_handler!(, 0, I1, I2, I3, 1, O1);
190implement_handler!(, 0, I1, I2, I3, 1, O1, O2);
191implement_handler!(, 0, I1, I2, I3, 1, O1, O2, O3);
192implement_handler!(, 0, I1, I2, I3, 1, O1, O2, O3, O4);
193implement_handler!(, 0, I1, I2, I3, 1, O1, O2, O3, O4, O5);
194implement_handler!(, 0, I1, I2, I3, 1, O1, O2, O3, O4, O5, O6);
195implement_handler!(, 0, I1, I2, I3, I4, 1,);
196implement_handler!(, 0, I1, I2, I3, I4, 1, O1);
197implement_handler!(, 0, I1, I2, I3, I4, 1, O1, O2);
198implement_handler!(, 0, I1, I2, I3, I4, 1, O1, O2, O3);
199implement_handler!(, 0, I1, I2, I3, I4, 1, O1, O2, O3, O4);
200implement_handler!(, 0, I1, I2, I3, I4, 1, O1, O2, O3, O4, O5);
201implement_handler!(, 0, I1, I2, I3, I4, 1, O1, O2, O3, O4, O5, O6);
202implement_handler!(, 0, I1, I2, I3, I4, I5, 1,);
203implement_handler!(, 0, I1, I2, I3, I4, I5, 1, O1);
204implement_handler!(, 0, I1, I2, I3, I4, I5, 1, O1, O2);
205implement_handler!(, 0, I1, I2, I3, I4, I5, 1, O1, O2, O3);
206implement_handler!(, 0, I1, I2, I3, I4, I5, 1, O1, O2, O3, O4);
207implement_handler!(, 0, I1, I2, I3, I4, I5, 1, O1, O2, O3, O4, O5);
208implement_handler!(, 0, I1, I2, I3, I4, I5, 1, O1, O2, O3, O4, O5, O6);
209implement_handler!(R1, 0,, 1,);
210implement_handler!(R1, 0,, 1, O1);
211implement_handler!(R1, 0,, 1, O1, O2);
212implement_handler!(R1, 0,, 1, O1, O2, O3);
213implement_handler!(R1, 0, I1, 1,);
214implement_handler!(R1, 0, I1, 1, O1);
215implement_handler!(R1, 0, I1, 1, O1, O2);
216implement_handler!(R1, 0, I1, 1, O1, O2, O3);
217implement_handler!(R1, 0, I1, 1, O1, O2, O3, O4);
218implement_handler!(R1, 0, I1, I2, 1,);
219implement_handler!(R1, 0, I1, I2, 1, O1);
220implement_handler!(R1, 0, I1, I2, 1, O1, O2);
221implement_handler!(R1, 0, I1, I2, 1, O1, O2, O3);
222implement_handler!(R1, 0, I1, I2, 1, O1, O2, O3, O4);
223implement_handler!(R1, 0, I1, I2, 1, O1, O2, O3, O4, O5);
224implement_handler!(R1, 0, I1, I2, I3, 1,);
225implement_handler!(R1, 0, I1, I2, I3, 1, O1);
226implement_handler!(R1, 0, I1, I2, I3, 1, O1, O2);
227implement_handler!(R1, 0, I1, I2, I3, 1, O1, O2, O3);
228implement_handler!(R1, 0, I1, I2, I3, 1, O1, O2, O3, O4);
229implement_handler!(R1, 0, I1, I2, I3, 1, O1, O2, O3, O4, O5);
230implement_handler!(R1, 0, I1, I2, I3, 1, O1, O2, O3, O4, O5, O6);
231implement_handler!(R1, 0, I1, I2, I3, I4, 1,);
232implement_handler!(R1, 0, I1, I2, I3, I4, 1, O1);
233implement_handler!(R1, 0, I1, I2, I3, I4, 1, O1, O2);
234implement_handler!(R1, 0, I1, I2, I3, I4, 1, O1, O2, O3);
235implement_handler!(R1, 0, I1, I2, I3, I4, 1, O1, O2, O3, O4);
236implement_handler!(R1, 0, I1, I2, I3, I4, 1, O1, O2, O3, O4, O5);
237implement_handler!(R1, 0, I1, I2, I3, I4, 1, O1, O2, O3, O4, O5, O6);
238implement_handler!(R1, R2, 0,, 1,);
239implement_handler!(R1, R2, 0,, 1, O1);
240implement_handler!(R1, R2, 0,, 1, O1, O2);
241implement_handler!(R1, R2, 0,, 1, O1, O2, O3);
242implement_handler!(R1, R2, 0, I1, 1,);
243implement_handler!(R1, R2, 0, I1, 1, O1);
244implement_handler!(R1, R2, 0, I1, 1, O1, O2);
245implement_handler!(R1, R2, 0, I1, 1, O1, O2, O3);
246implement_handler!(R1, R2, 0, I1, 1, O1, O2, O3, O4);
247implement_handler!(R1, R2, 0, I1, I2, 1,);
248implement_handler!(R1, R2, 0, I1, I2, 1, O1);
249implement_handler!(R1, R2, 0, I1, I2, 1, O1, O2);
250implement_handler!(R1, R2, 0, I1, I2, 1, O1, O2, O3);
251implement_handler!(R1, R2, 0, I1, I2, 1, O1, O2, O3, O4);
252implement_handler!(R1, R2, 0, I1, I2, 1, O1, O2, O3, O4, O5);
253implement_handler!(R1, R2, 0, I1, I2, I3, 1,);
254implement_handler!(R1, R2, 0, I1, I2, I3, 1, O1);
255implement_handler!(R1, R2, 0, I1, I2, I3, 1, O1, O2);
256implement_handler!(R1, R2, 0, I1, I2, I3, 1, O1, O2, O3);
257implement_handler!(R1, R2, 0, I1, I2, I3, 1, O1, O2, O3, O4);
258implement_handler!(R1, R2, 0, I1, I2, I3, 1, O1, O2, O3, O4, O5);
259implement_handler!(R1, R2, 0, I1, I2, I3, 1, O1, O2, O3, O4, O5, O6);
260
261pub fn call_handler<R, I, O, C, const ASYNC: bool>(
262 context: C,
263 handler: &mut dyn Handler<R, I, O, C, ASYNC>,
264 params: &HandlerParams,
265) -> HandlerResult {
266 handler.call(context, params)
267}
268
269pub fn describe_handler<R, I, O, C, const ASYNC: bool>(
270 handler: &dyn Handler<R, I, O, C, ASYNC>,
271) -> (Vec<ResourceId>, Vec<ResourceId>, Vec<ResourceId>) {
272 handler.get_resource_ids()
273}