1use core::marker::PhantomData;
2
3use cgp_core::prelude::*;
4
5use crate::components::*;
6
7pub struct PipeHandlers<Providers>(pub PhantomData<Providers>);
8
9#[cgp_provider]
10impl<Context, Code, Input, Output, Providers> Handler<Context, Code, Input>
11 for PipeHandlers<Providers>
12where
13 Context: HasAsyncErrorType,
14 Providers: PipeHandler<Context, Code, Input, Output = Output>,
15 Code: Send,
16 Input: Send,
17 Output: Send,
18{
19 type Output = Output;
20
21 async fn handle(
22 context: &Context,
23 tag: PhantomData<Code>,
24 input: Input,
25 ) -> Result<Output, Context::Error> {
26 Providers::handle(context, tag, input).await
27 }
28}
29
30#[cgp_provider]
31impl<Context, Tag, Input, Output, Providers> TryComputer<Context, Tag, Input>
32 for PipeHandlers<Providers>
33where
34 Context: HasErrorType,
35 Providers: PipeTryComputer<Context, Tag, Input, Output = Output>,
36{
37 type Output = Output;
38
39 fn try_compute(
40 context: &Context,
41 tag: PhantomData<Tag>,
42 input: Input,
43 ) -> Result<Output, Context::Error> {
44 Providers::try_compute(context, tag, input)
45 }
46}
47
48#[cgp_provider]
49impl<Context, Tag, Input, Output, Providers> Computer<Context, Tag, Input>
50 for PipeHandlers<Providers>
51where
52 Providers: PipeComputer<Context, Tag, Input, Output = Output>,
53{
54 type Output = Output;
55
56 fn compute(context: &Context, tag: PhantomData<Tag>, input: Input) -> Output {
57 Providers::compute(context, tag, input)
58 }
59}
60
61#[async_trait]
62trait PipeHandler<Context, Code, Input>
63where
64 Context: HasAsyncErrorType,
65{
66 type Output;
67
68 async fn handle(
69 context: &Context,
70 _code: PhantomData<Code>,
71 input: Input,
72 ) -> Result<Self::Output, Context::Error>;
73}
74
75impl<Context, Code, Input, Output, CurrentProvider, RestProviders> PipeHandler<Context, Code, Input>
76 for Cons<CurrentProvider, RestProviders>
77where
78 Context: HasAsyncErrorType,
79 CurrentProvider: Handler<Context, Code, Input>,
80 RestProviders: PipeHandler<Context, Code, CurrentProvider::Output, Output = Output>,
81 Code: Send,
82 Input: Send,
83 Output: Send,
84{
85 type Output = Output;
86
87 async fn handle(
88 context: &Context,
89 tag: PhantomData<Code>,
90 input: Input,
91 ) -> Result<Output, Context::Error> {
92 let intermediate = CurrentProvider::handle(context, tag, input).await?;
93 RestProviders::handle(context, tag, intermediate).await
94 }
95}
96
97impl<Context, Code, Input> PipeHandler<Context, Code, Input> for Nil
98where
99 Context: HasAsyncErrorType,
100 Code: Send,
101 Input: Send,
102{
103 type Output = Input;
104
105 async fn handle(
106 _context: &Context,
107 _code: PhantomData<Code>,
108 input: Input,
109 ) -> Result<Input, Context::Error> {
110 Ok(input)
111 }
112}
113
114trait PipeTryComputer<Context, Code, Input>
115where
116 Context: HasErrorType,
117{
118 type Output;
119
120 fn try_compute(
121 context: &Context,
122 _code: PhantomData<Code>,
123 input: Input,
124 ) -> Result<Self::Output, Context::Error>;
125}
126
127impl<Context, Tag, Input, Output, CurrentProvider, RestProviders>
128 PipeTryComputer<Context, Tag, Input> for Cons<CurrentProvider, RestProviders>
129where
130 Context: HasErrorType,
131 CurrentProvider: TryComputer<Context, Tag, Input>,
132 RestProviders: PipeTryComputer<Context, Tag, CurrentProvider::Output, Output = Output>,
133{
134 type Output = Output;
135
136 fn try_compute(
137 context: &Context,
138 tag: PhantomData<Tag>,
139 input: Input,
140 ) -> Result<Output, Context::Error> {
141 let intermediate = CurrentProvider::try_compute(context, tag, input)?;
142 RestProviders::try_compute(context, tag, intermediate)
143 }
144}
145
146impl<Context, Code, Input> PipeTryComputer<Context, Code, Input> for Nil
147where
148 Context: HasErrorType,
149{
150 type Output = Input;
151
152 fn try_compute(
153 _context: &Context,
154 _code: PhantomData<Code>,
155 input: Input,
156 ) -> Result<Input, Context::Error> {
157 Ok(input)
158 }
159}
160
161trait PipeComputer<Context, Code, Input> {
162 type Output;
163
164 fn compute(context: &Context, _code: PhantomData<Code>, input: Input) -> Self::Output;
165}
166
167impl<Context, Tag, Input, Output, CurrentProvider, RestProviders> PipeComputer<Context, Tag, Input>
168 for Cons<CurrentProvider, RestProviders>
169where
170 CurrentProvider: Computer<Context, Tag, Input>,
171 RestProviders: PipeComputer<Context, Tag, CurrentProvider::Output, Output = Output>,
172{
173 type Output = Output;
174
175 fn compute(context: &Context, tag: PhantomData<Tag>, input: Input) -> Output {
176 let intermediate = CurrentProvider::compute(context, tag, input);
177 RestProviders::compute(context, tag, intermediate)
178 }
179}
180
181impl<Context, Code, Input> PipeComputer<Context, Code, Input> for Nil {
182 type Output = Input;
183
184 fn compute(_context: &Context, _code: PhantomData<Code>, input: Input) -> Input {
185 input
186 }
187}