1#![warn(missing_docs)]
2pub mod meta;
16pub use meta::{all as all_jigs, find as find_jig, JigMeta};
17
18#[doc(hidden)]
19pub use inventory;
20
21pub struct Request<T>(pub T);
23
24pub struct Response<T> {
27 pub inner: Result<T, String>,
29}
30
31impl<T> Response<T> {
32 pub fn ok(value: T) -> Self {
34 Self { inner: Ok(value) }
35 }
36 pub fn err(msg: impl Into<String>) -> Self {
38 Self {
39 inner: Err(msg.into()),
40 }
41 }
42 pub fn is_ok(&self) -> bool {
44 self.inner.is_ok()
45 }
46 pub fn is_err(&self) -> bool {
48 self.inner.is_err()
49 }
50}
51
52pub enum Branch<Req, Resp> {
55 Continue(Request<Req>),
57 Done(Response<Resp>),
59}
60
61pub trait Jig<In> {
65 type Out;
67 fn run(&self, input: In) -> Self::Out;
69}
70
71impl<In, Out, F> Jig<In> for F
72where
73 F: Fn(In) -> Out,
74{
75 type Out = Out;
76 fn run(&self, input: In) -> Out {
77 (self)(input)
78 }
79}
80
81pub struct Pending<F>(pub F);
87
88pub trait Step {
92 type Out;
94 type Fut: core::future::Future<Output = Self::Out>;
96 fn into_step(self) -> Self::Fut;
98}
99
100impl<T> Step for Request<T> {
101 type Out = Request<T>;
102 type Fut = core::future::Ready<Request<T>>;
103 fn into_step(self) -> Self::Fut {
104 core::future::ready(self)
105 }
106}
107
108impl<T> Step for Response<T> {
109 type Out = Response<T>;
110 type Fut = core::future::Ready<Response<T>>;
111 fn into_step(self) -> Self::Fut {
112 core::future::ready(self)
113 }
114}
115
116impl<R, P> Step for Branch<R, P> {
117 type Out = Branch<R, P>;
118 type Fut = core::future::Ready<Branch<R, P>>;
119 fn into_step(self) -> Self::Fut {
120 core::future::ready(self)
121 }
122}
123
124impl<F> Step for Pending<F>
125where
126 F: core::future::Future,
127{
128 type Out = F::Output;
129 type Fut = F;
130 fn into_step(self) -> Self::Fut {
131 self.0
132 }
133}
134
135impl<F> core::future::IntoFuture for Pending<F>
136where
137 F: core::future::Future,
138{
139 type Output = F::Output;
140 type IntoFuture = F;
141 fn into_future(self) -> F {
142 self.0
143 }
144}
145
146impl<F> Pending<F>
147where
148 F: core::future::Future + 'static,
149{
150 pub fn then<J, R>(self, jig: J) -> Pending<impl core::future::Future<Output = R::Out>>
153 where
154 J: Jig<F::Output, Out = R> + 'static,
155 R: Step + 'static,
156 {
157 Pending(async move {
158 let val = self.0.await;
159 jig.run(val).into_step().await
160 })
161 }
162}
163
164pub trait Status {
167 fn ok(&self) -> bool;
169 fn error(&self) -> Option<String> {
171 None
172 }
173}
174
175impl<T> Status for Request<T> {
176 fn ok(&self) -> bool {
177 true
178 }
179}
180
181impl<T> Status for Response<T> {
182 fn ok(&self) -> bool {
183 self.is_ok()
184 }
185 fn error(&self) -> Option<String> {
186 self.inner.as_ref().err().cloned()
187 }
188}
189
190impl<Req, Resp> Status for Branch<Req, Resp> {
191 fn ok(&self) -> bool {
192 match self {
193 Branch::Continue(_) => true,
194 Branch::Done(r) => r.is_ok(),
195 }
196 }
197 fn error(&self) -> Option<String> {
198 match self {
199 Branch::Continue(_) => None,
200 Branch::Done(r) => r.inner.as_ref().err().cloned(),
201 }
202 }
203}
204
205pub trait Merge<Resp> {
209 type Merged;
211 fn into_continue(self) -> Self::Merged;
213 fn from_done(resp: Response<Resp>) -> Self::Merged;
215}
216
217impl<NewReq, Resp> Merge<Resp> for Request<NewReq> {
218 type Merged = Branch<NewReq, Resp>;
219 fn into_continue(self) -> Self::Merged {
220 Branch::Continue(self)
221 }
222 fn from_done(resp: Response<Resp>) -> Self::Merged {
223 Branch::Done(resp)
224 }
225}
226
227impl<Resp> Merge<Resp> for Response<Resp> {
228 type Merged = Response<Resp>;
229 fn into_continue(self) -> Self::Merged {
230 self
231 }
232 fn from_done(resp: Response<Resp>) -> Self::Merged {
233 resp
234 }
235}
236
237impl<NewReq, Resp> Merge<Resp> for Branch<NewReq, Resp> {
238 type Merged = Branch<NewReq, Resp>;
239 fn into_continue(self) -> Self::Merged {
240 self
241 }
242 fn from_done(resp: Response<Resp>) -> Self::Merged {
243 Branch::Done(resp)
244 }
245}
246
247impl<T> Request<T> {
248 pub fn then<J, U>(self, jig: J) -> U
250 where
251 J: Jig<Request<T>, Out = U>,
252 {
253 jig.run(self)
254 }
255}
256
257impl<T> Response<T> {
258 pub fn then<J, U>(self, jig: J) -> Response<U>
260 where
261 J: Jig<Response<T>, Out = Response<U>>,
262 {
263 match self.inner {
264 Ok(_) => jig.run(self),
265 Err(e) => Response { inner: Err(e) },
266 }
267 }
268}
269
270impl<Req, Resp> Branch<Req, Resp> {
271 pub fn then<J>(self, jig: J) -> <J::Out as Merge<Resp>>::Merged
274 where
275 J: Jig<Request<Req>>,
276 J::Out: Merge<Resp>,
277 {
278 match self {
279 Branch::Continue(r) => <J::Out as Merge<Resp>>::into_continue(jig.run(r)),
280 Branch::Done(resp) => <J::Out as Merge<Resp>>::from_done(resp),
281 }
282 }
283}
284
285#[cfg(test)]
286mod tests;