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}