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