cgp_dispatch/providers/dispatchers/
dispatch_matchers.rs

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}