pipe_chain/pipe/
and.rs

1//! And combinator
2use crate::{Pipe, Result};
3use std::marker::PhantomData;
4use tuplify::{Extend, HList};
5
6/// Combinator that chains 2 pipes together
7pub trait AndExt<I, O, E, R> {
8    /// Chains 2 [`Pipe`]s one after another
9    ///
10    /// The 2 output are combined into a single [`HList`]
11    ///
12    /// Example:
13    /// ```rust
14    /// # use fatal_error::FatalError;
15    /// # use pipe_chain::{Pipe, AndExt, AndThenExt, tag, str::TagStrError, Incomplete};
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    /// assert_eq!(
38    ///     tag::<Error, _, _>("foo").and(tag("bar")).apply("foobar"),
39    ///     Ok(("", ("foo", "bar")))
40    /// );
41    ///
42    /// assert_eq!(
43    ///     tag::<Error, _, _>("foo").and(tag("boo")).apply("foobar"),
44    ///     Err(FatalError::Error(Error::Tag(TagStrError("boo".into(), "bar".into()))))
45    /// );
46    ///
47    /// assert_eq!(
48    ///     tag::<Error, _, _>("foo").and(tag("boo")).apply("foobo"),
49    ///     Err(FatalError::Error(Error::Incomplete(Incomplete::Size(1))))
50    /// );
51    /// ```
52    fn and<O2, R2, P>(self, p: P) -> And<Self, P, O, O2, R>
53    where
54        Self: Sized,
55        O: Extend<O2>,
56        O2: HList,
57        P: Pipe<R, O2, E, R2>,
58    {
59        And::new(self, p)
60    }
61
62    /// Chains 2 [`Pipe`]s one after another
63    ///
64    /// Only the output of the second pipe is returned
65    ///
66    /// Example:
67    /// ```rust
68    /// # use fatal_error::FatalError;
69    /// # use pipe_chain::{Pipe, AndExt, AndThenExt, tag, str::TagStrError, Incomplete};
70    /// # use std::error::Error as StdError;
71    /// # #[derive(Debug, PartialEq, Eq)]
72    /// # enum Error {
73    /// #     Incomplete(Incomplete),
74    /// #     Tag(TagStrError),
75    /// # }
76    /// #
77    /// # impl std::fmt::Display for Error {
78    /// #     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
79    /// #        write!(f, "{self:?}")
80    /// #     }
81    /// # }
82    /// # impl StdError for Error {}
83    /// #
84    /// # impl From<Incomplete> for Error {
85    /// #     fn from(value: Incomplete) -> Error { Error::Incomplete(value) }
86    /// # }
87    /// #
88    /// # impl From<TagStrError> for Error {
89    /// #     fn from(value: TagStrError) -> Error { Error::Tag(value) }
90    /// # }
91    /// assert_eq!(
92    ///     tag::<Error, _, _>("foo").and_other(tag("bar")).apply("foobar"),
93    ///     Ok(("", ("bar",)))
94    /// );
95    /// ```
96    fn and_other<O2, R2, P>(self, p: P) -> AndOther<Self, P, O, R>
97    where
98        Self: Sized,
99        P: Pipe<R, O2, E, R2>,
100    {
101        AndOther::new(self, p)
102    }
103
104    /// Chains 2 [`Pipe`]s one after another
105    ///
106    /// Only the output of the first pipe is returned
107    ///
108    /// Example:
109    /// ```rust
110    /// # use fatal_error::FatalError;
111    /// # use pipe_chain::{Pipe, AndExt, AndThenExt, tag, str::TagStrError, Incomplete};
112    /// # use std::error::Error as StdError;
113    /// # #[derive(Debug, PartialEq, Eq)]
114    /// # enum Error {
115    /// #     Incomplete(Incomplete),
116    /// #     Tag(TagStrError),
117    /// # }
118    /// #
119    /// # impl std::fmt::Display for Error {
120    /// #     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
121    /// #        write!(f, "{self:?}")
122    /// #     }
123    /// # }
124    /// # impl StdError for Error {}
125    /// #
126    /// # impl From<Incomplete> for Error {
127    /// #     fn from(value: Incomplete) -> Error { Error::Incomplete(value) }
128    /// # }
129    /// #
130    /// # impl From<TagStrError> for Error {
131    /// #     fn from(value: TagStrError) -> Error { Error::Tag(value) }
132    /// # }
133    /// assert_eq!(
134    ///     tag::<Error, _, _>("foo").and_self(tag("bar")).apply("foobar"),
135    ///     Ok(("", ("foo",)))
136    /// );
137    /// ```
138    fn and_self<O2, R2, P>(self, other: P) -> AndSelf<Self, P, R, O2>
139    where
140        Self: Sized,
141        P: Pipe<R, O2, E, R2>,
142    {
143        AndSelf::new(self, other)
144    }
145}
146
147impl<I, O, E, R, P> AndExt<I, O, E, R> for P where P: Pipe<I, O, E, R> {}
148
149/// [AndExt::and] implementation
150pub struct And<P, P1, O, O2, R> {
151    p:   P,
152    p1:  P1,
153    _o:  PhantomData<O>,
154    _o2: PhantomData<O2>,
155    _r:  PhantomData<R>,
156}
157
158impl<P, P1, O, O2, R> And<P, P1, O, O2, R> {
159    fn new(p: P, p1: P1) -> Self {
160        Self { p, p1, _o: PhantomData, _o2: PhantomData, _r: PhantomData }
161    }
162}
163
164impl<I, O, O2, E, R, R2, P, P1> Pipe<I, O::Output, E, R2> for And<P, P1, O, O2, R>
165where
166    O: Extend<O2>,
167    O2: HList,
168    P: Pipe<I, O, E, R>,
169    P1: Pipe<R, O2, E, R2>,
170{
171    fn apply(&mut self, input: I) -> Result<R2, O::Output, E> {
172        let (i, o) = self.p.apply(input)?;
173        self.p1.apply(i).map(|(i, o2)| (i, o.extend(o2)))
174    }
175}
176
177/// [AndExt::and_other] implementation
178pub struct AndOther<P1, P2, O, R>(P1, P2, PhantomData<O>, PhantomData<R>);
179
180impl<P1, P2, O, R> AndOther<P1, P2, O, R> {
181    fn new(p: P1, p1: P2) -> AndOther<P1, P2, O, R> {
182        AndOther(p, p1, PhantomData, PhantomData)
183    }
184}
185
186impl<I, O, E, R, O2, R2, P1, P2> Pipe<I, O2, E, R2> for AndOther<P1, P2, O, R>
187where
188    P1: Pipe<I, O, E, R>,
189    P2: Pipe<R, O2, E, R2>,
190{
191    fn apply(&mut self, input: I) -> Result<R2, O2, E> {
192        self.0.apply(input).and_then(|(i, _)| self.1.apply(i).map(|(i, o)| (i, o)))
193    }
194}
195
196/// [AndExt::and_self] implementation
197pub struct AndSelf<P1, P2, R, O2>(P1, P2, PhantomData<R>, PhantomData<O2>);
198
199impl<P1, P2, R, O2> AndSelf<P1, P2, R, O2> {
200    fn new(p: P1, p1: P2) -> AndSelf<P1, P2, R, O2> {
201        AndSelf(p, p1, PhantomData, PhantomData)
202    }
203}
204
205impl<I, O, E, R, O2, R2, P1, P2> Pipe<I, O, E, R2> for AndSelf<P1, P2, R, O2>
206where
207    P1: Pipe<I, O, E, R>,
208    P2: Pipe<R, O2, E, R2>,
209{
210    fn apply(&mut self, input: I) -> Result<R2, O, E> {
211        self.0.apply(input).and_then(|(i, o)| self.1.apply(i).map(|(i, _)| (i, o)))
212    }
213}