pipe_chain/pipe/
or.rs

1use crate::{Pipe, Result};
2use std::marker::PhantomData;
3use tuplify::Unpack;
4
5/// Or combinator
6pub trait OrExt<I, O, E, R> {
7    /// Apply the second [Pipe] if the first fails
8    ///
9    /// Example:
10    /// ```
11    /// # use fatal_error::FatalError;
12    /// # use pipe_chain::{Pipe, OrExt, tag, str::TagStrError, Incomplete};
13    /// # use std::error::Error as StdError;
14    /// # #[derive(Debug, PartialEq, Eq)]
15    /// # enum Error {
16    /// #     Incomplete(Incomplete),
17    /// #     Tag(TagStrError),
18    /// # }
19    /// #
20    /// # impl std::fmt::Display for Error {
21    /// #     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
22    /// #        write!(f, "{self:?}")
23    /// #     }
24    /// # }
25    /// # impl StdError for Error {}
26    /// #
27    /// # impl From<Incomplete> for Error {
28    /// #     fn from(value: Incomplete) -> Error { Error::Incomplete(value) }
29    /// # }
30    /// #
31    /// # impl From<TagStrError> for Error {
32    /// #     fn from(value: TagStrError) -> Error { Error::Tag(value) }
33    /// # }
34    /// assert_eq!(tag::<Error, _, _>("foo").or(tag("bar")).apply("foo"), Ok(("", ("foo",))));
35    ///
36    /// assert_eq!(tag::<Error, _, _>("foo").or(tag("boo")).apply("boo"), Ok(("", ("boo",))));
37    ///
38    /// assert_eq!(
39    ///     tag::<Error, _, _>("foo").or(tag("boo")).apply("something"),
40    ///     Err(FatalError::Error(Error::Tag(TagStrError("boo".into(), "som".into()))))
41    /// );
42    /// ```
43    fn or<P>(self, p: P) -> Or<Self, P>
44    where
45        Self: Sized,
46        I: Clone,
47        P: Pipe<I, O, E, R>,
48    {
49        Or::new(self, p)
50    }
51
52    /// Apply the second [Pipe] if the first fails discarding the output of the second pipe
53    ///
54    /// Example:
55    /// ```
56    /// # use fatal_error::FatalError;
57    /// # use pipe_chain::{Pipe, OrExt, 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, _, _>("foo").or_self(tag("bar")).apply("foo"),
81    ///     Ok(("", (Some("foo"),)))
82    /// );
83    ///
84    /// assert_eq!(
85    ///     tag::<Error, _, _>("foo").or_self(tag("boo")).apply("boo"),
86    ///     Ok(("", (None,)))
87    /// );
88    ///
89    /// assert_eq!(
90    ///     tag::<Error, _, _>("foo").or_self(tag("boo")).apply("something"),
91    ///     Err(FatalError::Error(Error::Tag(TagStrError("boo".into(), "som".into()))))
92    /// );
93    /// ```
94    fn or_self<O2, P>(self, p: P) -> OrSelf<O, O2, Self, P>
95    where
96        Self: Sized,
97        O: Unpack,
98        I: Clone,
99        P: Pipe<I, O2, E, R>,
100    {
101        OrSelf::new(self, p)
102    }
103
104    /// Apply the second [Pipe] if the first fails discarding the output of the first pipe
105    ///
106    /// Example:
107    /// ```
108    /// # use fatal_error::FatalError;
109    /// # use pipe_chain::{Pipe, OrExt, tag, str::TagStrError, Incomplete};
110    /// # use std::error::Error as StdError;
111    /// # #[derive(Debug, PartialEq, Eq)]
112    /// # enum Error {
113    /// #     Incomplete(Incomplete),
114    /// #     Tag(TagStrError),
115    /// # }
116    /// #
117    /// # impl std::fmt::Display for Error {
118    /// #     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
119    /// #        write!(f, "{self:?}")
120    /// #     }
121    /// # }
122    /// # impl StdError for Error {}
123    /// #
124    /// # impl From<Incomplete> for Error {
125    /// #     fn from(value: Incomplete) -> Error { Error::Incomplete(value) }
126    /// # }
127    /// #
128    /// # impl From<TagStrError> for Error {
129    /// #     fn from(value: TagStrError) -> Error { Error::Tag(value) }
130    /// # }
131    /// assert_eq!(
132    ///     tag::<Error, _, _>("foo").or_other(tag("bar")).apply("foo"),
133    ///     Ok(("", (None,)))
134    /// );
135    ///
136    /// assert_eq!(
137    ///     tag::<Error, _, _>("foo").or_other(tag("boo")).apply("boo"),
138    ///     Ok(("", (Some("boo"),)))
139    /// );
140    ///
141    /// assert_eq!(
142    ///     tag::<Error, _, _>("foo").or_other(tag("boo")).apply("something"),
143    ///     Err(FatalError::Error(Error::Tag(TagStrError("boo".into(), "som".into()))))
144    /// );
145    /// ```
146    fn or_other<O2, P>(self, p: P) -> OrOther<O, O2, Self, P>
147    where
148        Self: Sized,
149        I: Clone,
150        O2: Unpack,
151        P: Pipe<I, O2, E, R>,
152    {
153        OrOther::new(self, p)
154    }
155}
156
157impl<I, O, E, R, P> OrExt<I, O, E, R> for P where P: Pipe<I, O, E, R> {}
158
159/// [OrExt::or] implementation
160pub struct Or<P, P1> {
161    p:  P,
162    p1: P1,
163}
164
165impl<P, P1> Or<P, P1> {
166    fn new(p: P, p1: P1) -> Self { Self { p, p1 } }
167}
168
169impl<I, O, E, R, P, P1> Pipe<I, O, E, R> for Or<P, P1>
170where
171    P: Pipe<I, O, E, R>,
172    P1: Pipe<I, O, E, R>,
173    I: Clone,
174{
175    fn apply(&mut self, input: I) -> Result<R, O, E> {
176        match self.p.apply(input.clone()) {
177            x @ Ok(_) => x,
178            Err(x) => {
179                x.fatality()?;
180                self.p1.apply(input)
181            }
182        }
183    }
184}
185
186/// [OrExt::or_self] implementation
187pub struct OrSelf<O, O2, P, P1> {
188    p:  P,
189    p1: P1,
190    o:  PhantomData<O>,
191    o2: PhantomData<O2>,
192}
193
194impl<O, O2, P, P1> OrSelf<O, O2, P, P1> {
195    fn new(p: P, p1: P1) -> Self { Self { p, p1, o: PhantomData, o2: PhantomData } }
196}
197
198impl<I, O, O2, E, R, P, P1> Pipe<I, (Option<O::Output>,), E, R> for OrSelf<O, O2, P, P1>
199where
200    O: Unpack,
201    P: Pipe<I, O, E, R>,
202    P1: Pipe<I, O2, E, R>,
203    I: Clone,
204{
205    fn apply(&mut self, input: I) -> Result<R, (Option<O::Output>,), E> {
206        match self.p.apply(input.clone()).map(|(x, y)| (x, (Some(y.unpack()),))) {
207            x @ Ok(_) => x,
208            Err(x) => {
209                x.fatality()?;
210                self.p1.apply(input).map(|(x, _)| (x, (None,)))
211            }
212        }
213    }
214}
215
216/// [OrExt::or_other] implementation
217pub struct OrOther<O, O2, P, P1> {
218    p:  P,
219    p1: P1,
220    o:  PhantomData<O>,
221    o2: PhantomData<O2>,
222}
223
224impl<O, O2, P, P1> OrOther<O, O2, P, P1> {
225    fn new(p: P, p1: P1) -> Self { Self { p, p1, o: PhantomData, o2: PhantomData } }
226}
227
228impl<I, O, O2, E, R, P, P1> Pipe<I, (Option<O2::Output>,), E, R> for OrOther<O, O2, P, P1>
229where
230    O2: Unpack,
231    P: Pipe<I, O, E, R>,
232    P1: Pipe<I, O2, E, R>,
233    I: Clone,
234{
235    fn apply(&mut self, input: I) -> Result<R, (Option<O2::Output>,), E> {
236        match self.p.apply(input.clone()).map(|(x, _)| (x, (None,))) {
237            x @ Ok(_) => x,
238            Err(x) => {
239                x.fatality()?;
240                self.p1.apply(input).map(|(x, y)| (x, (Some(y.unpack()),)))
241            }
242        }
243    }
244}
245
246/// [any_of] implementation detail
247pub trait AnyOf<I, O, E, R> {
248    /// Process the input
249    fn apply_any_of(&mut self, input: I) -> Result<R, O, E>;
250}
251
252/// Similar to [OrExt::or] but with many possibilities at once
253///
254/// Example
255/// ```
256/// # use fatal_error::FatalError;
257/// # use pipe_chain::{Pipe, any_of, tag, str::TagStrError, Incomplete};
258/// # use std::error::Error as StdError;
259/// # #[derive(Debug, PartialEq, Eq)]
260/// # enum Error {
261/// #     Incomplete(Incomplete),
262/// #     Tag(TagStrError),
263/// # }
264/// #
265/// # impl std::fmt::Display for Error {
266/// #     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
267/// #        write!(f, "{self:?}")
268/// #     }
269/// # }
270/// # impl StdError for Error {}
271/// #
272/// # impl From<Incomplete> for Error {
273/// #     fn from(value: Incomplete) -> Error { Error::Incomplete(value) }
274/// # }
275/// #
276/// # impl From<TagStrError> for Error {
277/// #     fn from(value: TagStrError) -> Error { Error::Tag(value) }
278/// # }
279/// let mut p = any_of((tag::<Error, _, _>("foo"), tag("bar"), tag("baz")));
280///
281/// assert_eq!(p.apply("foo"), Ok(("", ("foo",))));
282///
283/// assert_eq!(p.apply("bar"), Ok(("", ("bar",))));
284///
285/// assert_eq!(p.apply("baz"), Ok(("", ("baz",))));
286///
287/// assert_eq!(
288///     p.apply("something"),
289///     Err(FatalError::Error(Error::Tag(TagStrError("baz".into(), "som".into()))))
290/// );
291/// ```
292pub fn any_of<I, O, E, R>(mut p: impl AnyOf<I, O, E, R>) -> impl Pipe<I, O, E, R> {
293    move |x| p.apply_any_of(x)
294}
295
296macro_rules! any_of_impl {
297    ($_head:ident) => {};
298    ($head:ident $($tail:ident) *) => {
299        any_of_impl!($($tail) *);
300
301        impl<I: Clone, O, E, R, $head: Pipe<I, O, E, R>, $($tail: Pipe<I, O, E, R>), *> AnyOf<I, O, E, R> for ($head, $($tail), *) {
302            #[allow(non_snake_case)]
303            fn apply_any_of(&mut self, input: I) -> Result<R, O, E> {
304                let ($head, $($tail), *) = self;
305                let e = $head.apply(input.clone());
306                if e.as_ref().map_or_else(|x|x.is_fatal(), |_| true) { return e; }
307                $(
308                    let e = $tail.apply(input.clone());
309                    if e.as_ref().map_or_else(|x|x.is_fatal(), |_| true) { return e; }
310                ) *
311                e
312            }
313        }
314    };
315}
316
317any_of_impl!(T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13 T14 T15 T16 T17 T18 T19 T20 T21 T22 T23 T24 T25 T26 T27 T28 T29 T30 T31 T32);