1#![warn(missing_docs)]
2pub mod meta;
20pub use meta::{ChainKind, ChainStep, JigDef, JigMeta};
21
22pub struct Request<T>(pub T);
24
25pub struct Response<T> {
28 pub inner: Result<T, String>,
30}
31
32impl<T> Response<T> {
33 pub fn ok(value: T) -> Self {
35 Self { inner: Ok(value) }
36 }
37 pub fn err(msg: impl Into<String>) -> Self {
39 Self {
40 inner: Err(msg.into()),
41 }
42 }
43 pub fn is_ok(&self) -> bool {
45 self.inner.is_ok()
46 }
47 pub fn is_err(&self) -> bool {
49 self.inner.is_err()
50 }
51}
52
53pub enum Branch<Req, Resp> {
56 Continue(Request<Req>),
58 Done(Response<Resp>),
60}
61
62pub trait Jig<In> {
66 type Out;
68 fn run(&self, input: In) -> Self::Out;
70}
71
72impl<In, Out, F> Jig<In> for F
73where
74 F: Fn(In) -> Out,
75{
76 type Out = Out;
77 fn run(&self, input: In) -> Out {
78 (self)(input)
79 }
80}
81
82pub struct Pending<F>(pub F);
88
89pub trait Step {
93 type Out;
95 type Fut: core::future::Future<Output = Self::Out>;
97 fn into_step(self) -> Self::Fut;
99}
100
101impl<T> Step for Request<T> {
102 type Out = Request<T>;
103 type Fut = core::future::Ready<Request<T>>;
104 fn into_step(self) -> Self::Fut {
105 core::future::ready(self)
106 }
107}
108
109impl<T> Step for Response<T> {
110 type Out = Response<T>;
111 type Fut = core::future::Ready<Response<T>>;
112 fn into_step(self) -> Self::Fut {
113 core::future::ready(self)
114 }
115}
116
117impl<R, P> Step for Branch<R, P> {
118 type Out = Branch<R, P>;
119 type Fut = core::future::Ready<Branch<R, P>>;
120 fn into_step(self) -> Self::Fut {
121 core::future::ready(self)
122 }
123}
124
125impl<F> Step for Pending<F>
126where
127 F: core::future::Future,
128{
129 type Out = F::Output;
130 type Fut = F;
131 fn into_step(self) -> Self::Fut {
132 self.0
133 }
134}
135
136impl<F> core::future::IntoFuture for Pending<F>
137where
138 F: core::future::Future,
139{
140 type Output = F::Output;
141 type IntoFuture = F;
142 fn into_future(self) -> F {
143 self.0
144 }
145}
146
147impl<F> Pending<F>
148where
149 F: core::future::Future + 'static,
150{
151 pub fn then<J, R>(self, jig: J) -> Pending<impl core::future::Future<Output = R::Out>>
154 where
155 J: Jig<F::Output, Out = R> + 'static,
156 R: Step + 'static,
157 {
158 Pending(async move {
159 let val = self.0.await;
160 jig.run(val).into_step().await
161 })
162 }
163}
164
165pub trait Status {
168 fn ok(&self) -> bool;
170 fn error(&self) -> Option<String> {
172 None
173 }
174}
175
176impl<T> Status for Request<T> {
177 fn ok(&self) -> bool {
178 true
179 }
180}
181
182impl<T> Status for Response<T> {
183 fn ok(&self) -> bool {
184 self.is_ok()
185 }
186 fn error(&self) -> Option<String> {
187 self.inner.as_ref().err().cloned()
188 }
189}
190
191impl<Req, Resp> Status for Branch<Req, Resp> {
192 fn ok(&self) -> bool {
193 match self {
194 Branch::Continue(_) => true,
195 Branch::Done(r) => r.is_ok(),
196 }
197 }
198 fn error(&self) -> Option<String> {
199 match self {
200 Branch::Continue(_) => None,
201 Branch::Done(r) => r.inner.as_ref().err().cloned(),
202 }
203 }
204}
205
206pub trait Merge<Resp> {
210 type Merged;
212 fn into_continue(self) -> Self::Merged;
214 fn from_done(resp: Response<Resp>) -> Self::Merged;
216}
217
218impl<NewReq, Resp> Merge<Resp> for Request<NewReq> {
219 type Merged = Branch<NewReq, Resp>;
220 fn into_continue(self) -> Self::Merged {
221 Branch::Continue(self)
222 }
223 fn from_done(resp: Response<Resp>) -> Self::Merged {
224 Branch::Done(resp)
225 }
226}
227
228impl<Resp> Merge<Resp> for Response<Resp> {
229 type Merged = Response<Resp>;
230 fn into_continue(self) -> Self::Merged {
231 self
232 }
233 fn from_done(resp: Response<Resp>) -> Self::Merged {
234 resp
235 }
236}
237
238impl<NewReq, Resp> Merge<Resp> for Branch<NewReq, Resp> {
239 type Merged = Branch<NewReq, Resp>;
240 fn into_continue(self) -> Self::Merged {
241 self
242 }
243 fn from_done(resp: Response<Resp>) -> Self::Merged {
244 Branch::Done(resp)
245 }
246}
247
248impl<T> Request<T> {
249 pub fn then<J, U>(self, jig: J) -> U
251 where
252 J: Jig<Request<T>, Out = U>,
253 {
254 jig.run(self)
255 }
256}
257
258impl<T> Response<T> {
259 pub fn then<J, U>(self, jig: J) -> Response<U>
263 where
264 J: Jig<Response<T>, Out = Response<U>>,
265 {
266 jig.run(self)
267 }
268}
269
270#[macro_export]
284macro_rules! fork {
285 ($req:expr, $($pred:expr => $jig:expr,)+ _ => $default:expr $(,)?) => {{
286 let __req = $req;
287 $crate::__fork_chain!(__req, $($pred => $jig,)+ ; $default)
288 }};
289}
290
291#[doc(hidden)]
292#[macro_export]
293macro_rules! __fork_chain {
294 ($req:ident, $pred:expr => $jig:expr, $($rest_p:expr => $rest_j:expr,)* ; $default:expr) => {
295 if ($pred)(&$req.0) {
296 ($jig)($req)
297 } else {
298 $crate::__fork_chain!($req, $($rest_p => $rest_j,)* ; $default)
299 }
300 };
301 ($req:ident, ; $default:expr) => {
302 ($default)($req)
303 };
304}
305
306impl<Req, Resp> Branch<Req, Resp> {
307 pub fn then<J>(self, jig: J) -> <J::Out as Merge<Resp>>::Merged
310 where
311 J: Jig<Request<Req>>,
312 J::Out: Merge<Resp>,
313 {
314 match self {
315 Branch::Continue(r) => <J::Out as Merge<Resp>>::into_continue(jig.run(r)),
316 Branch::Done(resp) => <J::Out as Merge<Resp>>::from_done(resp),
317 }
318 }
319}
320
321#[cfg(test)]
322mod tests;