pipe_chain/pipe/
and_then.rs

1//! AndThen combinator
2use crate::{Pipe, Result};
3use fatal_error::FatalError;
4use std::marker::PhantomData;
5use tuplify::{FunMut, HList};
6
7/// Combinator that applies a faillible function on the output of a pipe
8pub trait AndThenExt<I, O, E, R> {
9    /// Applies the given closure on the output of the pipe
10    ///
11    /// the output of both [`Pipe`] and closure and must be an [`HList`]
12    ///
13    /// ```rust
14    /// # use pipe_chain::{Pipe, AndExt, AndThenExt, tag, str::TagStrError, Incomplete};
15    /// # use fatal_error::FatalError;
16    /// # use std::error::Error as StdError;
17    /// # #[derive(Debug, PartialEq, Eq)]
18    /// # enum Error {
19    /// #     Incomplete(Incomplete),
20    /// #     Tag(TagStrError),
21    /// # }
22    /// #
23    /// # impl std::fmt::Display for Error {
24    /// #     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
25    /// #        write!(f, "{self:?}")
26    /// #     }
27    /// # }
28    /// # impl StdError for Error {}
29    /// #
30    /// # impl From<Incomplete> for Error {
31    /// #     fn from(value: Incomplete) -> Error { Error::Incomplete(value) }
32    /// # }
33    /// #
34    /// # impl From<TagStrError> for Error {
35    /// #     fn from(value: TagStrError) -> Error { Error::Tag(value) }
36    /// # }
37    /// fn yolo(_: &str, _: &str) -> Result<(u8, u8), FatalError<Error>> { Ok((1, 2)) }
38    ///
39    /// assert_eq!(
40    ///     tag::<Error, _, _>("1").and(tag("2")).and_then(yolo).apply("12"),
41    ///     Ok(("", (1u8, 2u8)))
42    /// )
43    /// ```
44    fn and_then<O2, F>(self, f: F) -> AndThen<O, Self, F>
45    where
46        Self: Sized,
47        F: FunMut<O, Output = std::result::Result<O2, FatalError<E>>>,
48        O: HList,
49        O2: HList,
50    {
51        AndThen::new(self, f)
52    }
53
54    /// Applies the given closure on the output of a pipe
55    ///
56    /// ```rust
57    /// # use pipe_chain::{Pipe, AndExt, AndThenExt, tag, str::TagStrError, Incomplete};
58    /// # use std::error::Error as StdError;
59    /// # #[derive(Debug, PartialEq, Eq)]
60    /// # enum Error {
61    /// #     Incomplete(Incomplete),
62    /// #     Tag(TagStrError),
63    /// # }
64    /// #
65    /// # impl std::fmt::Display for Error {
66    /// #     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
67    /// #        write!(f, "{self:?}")
68    /// #     }
69    /// # }
70    /// # impl StdError for Error {}
71    /// #
72    /// # impl From<Incomplete> for Error {
73    /// #     fn from(value: Incomplete) -> Error { Error::Incomplete(value) }
74    /// # }
75    /// #
76    /// # impl From<TagStrError> for Error {
77    /// #     fn from(value: TagStrError) -> Error { Error::Tag(value) }
78    /// # }
79    /// assert_eq!(
80    ///     tag::<Error, _, _>("1")
81    ///         .and(tag("2"))
82    ///         .and_thenf(|(first, second)| Ok(12))
83    ///         .apply("12"),
84    ///     Ok(("", 12))
85    /// )
86    /// ```
87    fn and_thenf<O2, F>(self, f: F) -> AndThenF<O, Self, F>
88    where
89        Self: Sized,
90        F: FnMut(O) -> std::result::Result<O2, FatalError<E>>,
91    {
92        AndThenF::new(self, f)
93    }
94
95    /// Applies the given closure to the output and remaining input of a pipe
96    ///
97    /// ```
98    /// # use pipe_chain::{Pipe, AndExt, AndThenExt, tag, str::TagStrError, Incomplete, Result, MapExt, OrExt};
99    /// # use std::error::Error as StdError;
100    /// # #[derive(Debug, PartialEq, Eq)]
101    /// # enum Error {
102    /// #     Incomplete(Incomplete),
103    /// #     Tag(TagStrError),
104    /// # }
105    /// #
106    /// # impl std::fmt::Display for Error {
107    /// #     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
108    /// #        write!(f, "{self:?}")
109    /// #     }
110    /// # }
111    /// # impl StdError for Error {}
112    /// #
113    /// # impl From<Incomplete> for Error {
114    /// #     fn from(value: Incomplete) -> Error { Error::Incomplete(value) }
115    /// # }
116    /// #
117    /// # impl From<TagStrError> for Error {
118    /// #     fn from(value: TagStrError) -> Error { Error::Tag(value) }
119    /// # }
120    ///
121    /// #[derive(Debug, PartialEq, Eq)]
122    /// enum FooBar {
123    ///     Foo,
124    ///     Bar,
125    /// }
126    ///
127    /// fn true_or_false(input: &str) -> Result<&str, (bool,), Error> {
128    ///     tag("true").map1(|_| true).or(tag("false").map1(|_| false)).apply(input)
129    /// }
130    ///
131    /// fn foobar(input: &str) -> Result<&str, (FooBar,), Error> {
132    ///     true_or_false
133    ///         .ok_and_then(|x, (y,)| {
134    ///             if y {
135    ///                 tag("bar").map1(|_| FooBar::Bar).apply(x)
136    ///             } else {
137    ///                 tag("foo").map1(|_| FooBar::Foo).apply(x)
138    ///             }
139    ///         })
140    ///         .apply(input)
141    /// }
142    ///
143    /// assert_eq!(foobar("truebar"), Ok(("", (FooBar::Bar,))));
144    /// assert_eq!(foobar("falsefoo"), Ok(("", (FooBar::Foo,))));
145    /// assert_eq!(
146    ///     tag::<Error, _, _>("1")
147    ///         .and(tag("2"))
148    ///         .ok_and_then(|r, (first, second)| Ok(("yolo", (12,))))
149    ///         .apply("12"),
150    ///     Ok(("yolo", (12,)))
151    /// )
152    /// ```
153    fn ok_and_then<O2, R2, F>(self, other: F) -> OkAndThen<O, R, Self, F>
154    where
155        Self: Sized,
156        F: FunMut<(R, O), Output = std::result::Result<(R2, O2), FatalError<E>>>,
157    {
158        OkAndThen::new(self, other)
159    }
160
161    /// Applies the pipes consecutively
162    ///
163    /// the output of both [`Pipe`] and closure and must be an [`HList`]
164    ///
165    /// ```rust
166    /// # use pipe_chain::{Pipe, AndExt, AndThenExt, tag, str::TagStrError, Incomplete, MapExt, OrExt, Result};
167    /// # use fatal_error::FatalError;
168    /// # use std::error::Error as StdError;
169    /// # #[derive(Debug, PartialEq, Eq)]
170    /// # enum Error {
171    /// #     Incomplete(Incomplete),
172    /// #     Tag(TagStrError),
173    /// # }
174    /// #
175    /// # impl std::fmt::Display for Error {
176    /// #     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
177    /// #        write!(f, "{self:?}")
178    /// #     }
179    /// # }
180    /// # impl StdError for Error {}
181    /// #
182    /// # impl From<Incomplete> for Error {
183    /// #     fn from(value: Incomplete) -> Error { Error::Incomplete(value) }
184    /// # }
185    /// #
186    /// # impl From<TagStrError> for Error {
187    /// #     fn from(value: TagStrError) -> Error { Error::Tag(value) }
188    /// # }
189    /// #[derive(Debug, PartialEq, Eq)]
190    /// enum FooBar {
191    ///     Foo,
192    ///     Bar,
193    /// }
194    ///
195    /// fn true_or_false(input: &str) -> Result<&str, (bool,), Error> {
196    ///     tag("true").map1(|_| true).or(tag("false").map1(|_| false)).apply(input)
197    /// }
198    ///
199    /// fn foobar(input: &str) -> Result<&str, (FooBar,), Error> {
200    ///     true_or_false
201    ///         .ok_then(|(x, (y,))| {
202    ///             if y {
203    ///                 tag("bar").map1(|_| FooBar::Bar).apply(x)
204    ///             } else {
205    ///                 tag("foo").map1(|_| FooBar::Foo).apply(x)
206    ///             }
207    ///         })
208    ///         .apply(input)
209    /// }
210    ///
211    /// assert_eq!(
212    ///     tag::<Error, _, _>("1")
213    ///         .and(tag("2"))
214    ///         .ok_then(|(r, (first, second))| Ok(("yolo", (12,))))
215    ///         .apply("12"),
216    ///     Ok(("yolo", (12,)))
217    /// );
218    ///
219    /// assert_eq!(foobar("truebar"), Ok(("", (FooBar::Bar,))));
220    /// assert_eq!(foobar("falsefoo"), Ok(("", (FooBar::Foo,))));
221    /// ```
222    #[inline]
223    fn ok_then<O2, R2, P>(self, other: P) -> OkThen<O, R, Self, P>
224    where
225        Self: Pipe<I, O, E, R> + Sized,
226        P: Pipe<(R, O), O2, E, R2> + Sized,
227    {
228        OkThen::new(self, other)
229    }
230}
231
232impl<I, O, E, R, P> AndThenExt<I, O, E, R> for P where P: Pipe<I, O, E, R> {}
233
234/// [AndThenExt::and_then] implementation
235pub struct AndThen<O, P, F>(P, F, PhantomData<O>);
236
237impl<O, P, F> AndThen<O, P, F> {
238    fn new(p: P, f: F) -> Self { AndThen(p, f, PhantomData) }
239}
240
241impl<I, O, O2, E, R, P, F> Pipe<I, O2, E, R> for AndThen<O, P, F>
242where
243    O: HList,
244    P: Pipe<I, O, E, R>,
245    F: FunMut<O, Output = std::result::Result<O2, FatalError<E>>>,
246{
247    fn apply(&mut self, input: I) -> Result<R, O2, E> {
248        self.0.apply(input).and_then(|(x, y)| Ok((x, self.1.call_fun_mut(y)?)))
249    }
250}
251
252/// [AndThenExt::and_thenf] implementation
253pub struct AndThenF<O, P, F>(P, F, PhantomData<O>);
254
255impl<O, P, F> AndThenF<O, P, F> {
256    fn new(p: P, f: F) -> Self { AndThenF(p, f, PhantomData) }
257}
258
259impl<I, O, O2, E, R, P, F> Pipe<I, O2, E, R> for AndThenF<O, P, F>
260where
261    O: HList,
262    P: Pipe<I, O, E, R>,
263    F: FnMut(O) -> std::result::Result<O2, FatalError<E>>,
264{
265    fn apply(&mut self, input: I) -> Result<R, O2, E> {
266        self.0.apply(input).and_then(|(x, y)| Ok((x, self.1(y)?)))
267    }
268}
269
270/// [AndThenExt::ok_and_then] implementation
271pub struct OkAndThen<O, R, P, P1>(P, P1, PhantomData<O>, PhantomData<R>);
272
273impl<O, R, P, P1> OkAndThen<O, R, P, P1> {
274    fn new(p: P, p1: P1) -> Self { Self(p, p1, PhantomData, PhantomData) }
275}
276
277impl<I, O, O2, E, R, R2, P, F> Pipe<I, O2, E, R2> for OkAndThen<O, R, P, F>
278where
279    P: Pipe<I, O, E, R>,
280    F: FunMut<(R, O), Output = std::result::Result<(R2, O2), FatalError<E>>>,
281{
282    fn apply(&mut self, input: I) -> Result<R2, O2, E> {
283        self.1.call_fun_mut(self.0.apply(input)?)
284    }
285}
286
287/// [AndThenExt::ok_then] implementation
288pub struct OkThen<O, R, P, P1>(P, P1, PhantomData<O>, PhantomData<R>);
289
290impl<O, R, P, P1> OkThen<O, R, P, P1> {
291    fn new(p: P, p1: P1) -> Self { OkThen(p, p1, PhantomData, PhantomData) }
292}
293
294impl<I, O, O2, E, R, R2, P, P1> Pipe<I, O2, E, R2> for OkThen<O, R, P, P1>
295where
296    O: HList,
297    P: Pipe<I, O, E, R>,
298    P1: Pipe<(R, O), O2, E, R2>,
299{
300    fn apply(&mut self, input: I) -> Result<R2, O2, E> {
301        self.0.apply(input).and_then(|x| self.1.apply(x))
302    }
303}