1use core::marker::PhantomData;
2
3use cgp_core::prelude::*;
4use cgp_handler::{
5 Computer, ComputerComponent, Handler, HandlerComponent, TryComputer, TryComputerComponent,
6};
7
8pub struct DispatchMatchers<Handlers>(pub PhantomData<Handlers>);
9
10#[cgp_provider]
11impl<Context, Code, Input, Handlers, Output, Remainder> Computer<Context, Code, Input>
12 for DispatchMatchers<Handlers>
13where
14 Handlers: DispatchComputer<Context, Code, Input, Output = Output, Remainder = Remainder>,
15{
16 type Output = Result<Output, Remainder>;
17
18 fn compute(_context: &Context, code: PhantomData<Code>, input: Input) -> Self::Output {
19 Handlers::compute(_context, code, input)
20 }
21}
22
23#[cgp_provider]
24impl<Context, Code, Input, Handlers, Output, Remainder> TryComputer<Context, Code, Input>
25 for DispatchMatchers<Handlers>
26where
27 Context: HasErrorType,
28 Handlers: TryDispatchComputer<Context, Code, Input, Output = Output, Remainder = Remainder>,
29{
30 type Output = Result<Output, Remainder>;
31
32 fn try_compute(
33 _context: &Context,
34 code: PhantomData<Code>,
35 input: Input,
36 ) -> Result<Self::Output, Context::Error> {
37 Handlers::try_compute(_context, code, input)
38 }
39}
40
41#[cgp_provider]
42impl<Context, Code: Send, Input: Send, Handlers, Output: Send, Remainder: Send>
43 Handler<Context, Code, Input> for DispatchMatchers<Handlers>
44where
45 Context: HasAsyncErrorType,
46 Handlers: DispatchHandler<Context, Code, Input, Output = Output, Remainder = Remainder>,
47{
48 type Output = Result<Output, Remainder>;
49
50 async fn handle(
51 _context: &Context,
52 code: PhantomData<Code>,
53 input: Input,
54 ) -> Result<Self::Output, Context::Error> {
55 Handlers::handle(_context, code, input).await
56 }
57}
58
59trait DispatchComputer<Context, Code, Input> {
60 type Output;
61
62 type Remainder;
63
64 fn compute(
65 context: &Context,
66 tag: PhantomData<Code>,
67 input: Input,
68 ) -> Result<Self::Output, Self::Remainder>;
69}
70
71trait TryDispatchComputer<Context, Code, Input>
72where
73 Context: HasErrorType,
74{
75 type Output;
76
77 type Remainder;
78
79 fn try_compute(
80 context: &Context,
81 tag: PhantomData<Code>,
82 input: Input,
83 ) -> Result<Result<Self::Output, Self::Remainder>, Context::Error>;
84}
85
86impl<
87 Context,
88 Code,
89 Input,
90 CurrentHandler,
91 NextHandler,
92 RestHandlers,
93 Output,
94 RemainderA,
95 RemainderB,
96 > DispatchComputer<Context, Code, Input>
97 for Cons<CurrentHandler, Cons<NextHandler, RestHandlers>>
98where
99 CurrentHandler: Computer<Context, Code, Input, Output = Result<Output, RemainderA>>,
100 Cons<NextHandler, RestHandlers>:
101 DispatchComputer<Context, Code, RemainderA, Output = Output, Remainder = RemainderB>,
102{
103 type Output = Output;
104
105 type Remainder = RemainderB;
106
107 fn compute(
108 context: &Context,
109 tag: PhantomData<Code>,
110 input: Input,
111 ) -> Result<Self::Output, Self::Remainder> {
112 let res = CurrentHandler::compute(context, tag, input);
113
114 match res {
115 Ok(output) => Ok(output),
116 Err(remainder) => Cons::compute(context, tag, remainder),
117 }
118 }
119}
120
121impl<
122 Context,
123 Code,
124 Input,
125 CurrentHandler,
126 NextHandler,
127 RestHandlers,
128 Output,
129 RemainderA,
130 RemainderB,
131 > TryDispatchComputer<Context, Code, Input>
132 for Cons<CurrentHandler, Cons<NextHandler, RestHandlers>>
133where
134 Context: HasErrorType,
135 CurrentHandler: TryComputer<Context, Code, Input, Output = Result<Output, RemainderA>>,
136 Cons<NextHandler, RestHandlers>:
137 TryDispatchComputer<Context, Code, RemainderA, Output = Output, Remainder = RemainderB>,
138{
139 type Output = Output;
140
141 type Remainder = RemainderB;
142
143 fn try_compute(
144 context: &Context,
145 tag: PhantomData<Code>,
146 input: Input,
147 ) -> Result<Result<Self::Output, Self::Remainder>, Context::Error> {
148 let res = CurrentHandler::try_compute(context, tag, input)?;
149
150 match res {
151 Ok(output) => Ok(Ok(output)),
152 Err(remainder) => Cons::try_compute(context, tag, remainder),
153 }
154 }
155}
156
157impl<Context, Code, Input, Handler, Remainder, Output> DispatchComputer<Context, Code, Input>
158 for Cons<Handler, Nil>
159where
160 Handler: Computer<Context, Code, Input, Output = Result<Output, Remainder>>,
161{
162 type Output = Output;
163
164 type Remainder = Remainder;
165
166 fn compute(
167 context: &Context,
168 tag: PhantomData<Code>,
169 input: Input,
170 ) -> Result<Self::Output, Self::Remainder> {
171 Handler::compute(context, tag, input)
172 }
173}
174
175impl<Context, Code, Input, Handler, Remainder, Output> TryDispatchComputer<Context, Code, Input>
176 for Cons<Handler, Nil>
177where
178 Context: HasErrorType,
179 Handler: TryComputer<Context, Code, Input, Output = Result<Output, Remainder>>,
180{
181 type Output = Output;
182
183 type Remainder = Remainder;
184
185 fn try_compute(
186 context: &Context,
187 tag: PhantomData<Code>,
188 input: Input,
189 ) -> Result<Result<Self::Output, Self::Remainder>, Context::Error> {
190 Handler::try_compute(context, tag, input)
191 }
192}
193
194#[async_trait]
195trait DispatchHandler<Context, Code, Input>
196where
197 Context: HasErrorType,
198{
199 type Output;
200
201 type Remainder;
202
203 async fn handle(
204 context: &Context,
205 tag: PhantomData<Code>,
206 input: Input,
207 ) -> Result<Result<Self::Output, Self::Remainder>, Context::Error>;
208}
209
210impl<
211 Context,
212 Code: Send,
213 Input: Send,
214 CurrentHandler,
215 NextHandler,
216 RestHandlers,
217 Output: Send,
218 RemainderA: Send,
219 RemainderB: Send,
220 > DispatchHandler<Context, Code, Input>
221 for Cons<CurrentHandler, Cons<NextHandler, RestHandlers>>
222where
223 Context: HasAsyncErrorType,
224 CurrentHandler: Handler<Context, Code, Input, Output = Result<Output, RemainderA>>,
225 Cons<NextHandler, RestHandlers>:
226 DispatchHandler<Context, Code, RemainderA, Output = Output, Remainder = RemainderB>,
227{
228 type Output = Output;
229
230 type Remainder = RemainderB;
231
232 async fn handle(
233 context: &Context,
234 tag: PhantomData<Code>,
235 input: Input,
236 ) -> Result<Result<Self::Output, Self::Remainder>, Context::Error> {
237 let res = CurrentHandler::handle(context, tag, input).await?;
238
239 match res {
240 Ok(output) => Ok(Ok(output)),
241 Err(remainder) => Cons::handle(context, tag, remainder).await,
242 }
243 }
244}
245
246impl<Context, Code: Send, Input: Send, CurrentHandler, Remainder: Send, Output: Send>
247 DispatchHandler<Context, Code, Input> for Cons<CurrentHandler, Nil>
248where
249 Context: HasAsyncErrorType,
250 CurrentHandler: Handler<Context, Code, Input, Output = Result<Output, Remainder>>,
251{
252 type Output = Output;
253
254 type Remainder = Remainder;
255
256 async fn handle(
257 context: &Context,
258 tag: PhantomData<Code>,
259 input: Input,
260 ) -> Result<Result<Self::Output, Self::Remainder>, Context::Error> {
261 CurrentHandler::handle(context, tag, input).await
262 }
263}