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}