pipe_chain/pipe/
map.rs

1use crate::{Pipe, Result};
2use fatal_error::FatalError;
3use std::marker::PhantomData;
4use tuplify::{FunMut, HList};
5
6/// Combinator that transforms a part of a pipe
7pub trait MapExt<I, O, E, R> {
8    /// Maps the output of a pipe `O` to `O2` by applying a function to it.
9    ///
10    /// Example:
11    /// ```
12    /// # use pipe_chain::{tag, str::TagStrError, MapExt, Pipe, Incomplete};
13    /// # use fatal_error::FatalError;
14    /// # use std::error::Error as StdError;
15    /// # #[derive(Debug, PartialEq, Eq)]
16    /// # enum Error {
17    /// #     Incomplete(Incomplete),
18    /// #     Tag(TagStrError),
19    /// # }
20    /// #
21    /// # impl std::fmt::Display for Error {
22    /// #     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
23    /// #        write!(f, "{self:?}")
24    /// #     }
25    /// # }
26    /// # impl StdError for Error {}
27    /// #
28    /// # impl From<Incomplete> for Error {
29    /// #     fn from(value: Incomplete) -> Error { Error::Incomplete(value) }
30    /// # }
31    /// #
32    /// # impl From<TagStrError> for Error {
33    /// #     fn from(value: TagStrError) -> Error { Error::Tag(value) }
34    /// # }
35    /// assert_eq!(
36    ///     tag::<Error, _, _>("a").map(|_| (1, 2, 3)).apply("a"),
37    ///     Ok(("", (1, 2, 3)))
38    /// );
39    /// ```
40    fn map<F>(self, f: F) -> Map<Self, F, O>
41    where
42        Self: Sized,
43        O: HList,
44        F: FunMut<O>,
45    {
46        Map::new(self, f)
47    }
48    /// Maps the output of a pipe `O` to `O2` by applying a function to it.
49    /// The result is mapped into a tuple
50    /// ```
51    /// # use pipe_chain::{tag, str::TagStrError, MapExt, Pipe, Incomplete};
52    /// # use fatal_error::FatalError;
53    /// # use std::error::Error as StdError;
54    /// # #[derive(Debug, PartialEq, Eq)]
55    /// # enum Error {
56    /// #     Incomplete(Incomplete),
57    /// #     Tag(TagStrError),
58    /// # }
59    /// #
60    /// # impl std::fmt::Display for Error {
61    /// #     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
62    /// #        write!(f, "{self:?}")
63    /// #     }
64    /// # }
65    /// # impl StdError for Error {}
66    /// #
67    /// # impl From<Incomplete> for Error {
68    /// #     fn from(value: Incomplete) -> Error { Error::Incomplete(value) }
69    /// # }
70    /// #
71    /// # impl From<TagStrError> for Error {
72    /// #     fn from(value: TagStrError) -> Error { Error::Tag(value) }
73    /// # }
74    /// assert_eq!(
75    ///     tag::<Error, _, _>("a").map1(|_| (1, 2, 3)).apply("a"),
76    ///     Ok(("", ((1, 2, 3),)))
77    /// );
78    /// assert_eq!(tag::<Error, _, _>("a").map1(|_| 1).apply("a"), Ok(("", (1,))));
79    /// ```
80    fn map1<F>(self, f: F) -> Map1<Self, F, O>
81    where
82        Self: Sized,
83        O: HList,
84        F: FunMut<O>,
85    {
86        Map1::new(self, f)
87    }
88
89    /// Maps the output of a pipe `O` to `O2` by applying a function to it.
90    /// The result is mapped into a tuple
91    /// ```
92    /// # use pipe_chain::{tag, str::TagStrError, MapExt, Pipe, Incomplete};
93    /// # use fatal_error::FatalError;
94    /// # use std::error::Error as StdError;
95    /// # #[derive(Debug, PartialEq, Eq)]
96    /// # enum Error {
97    /// #     Incomplete(Incomplete),
98    /// #     Tag(TagStrError),
99    /// # }
100    /// #
101    /// # impl std::fmt::Display for Error {
102    /// #     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
103    /// #        write!(f, "{self:?}")
104    /// #     }
105    /// # }
106    /// # impl StdError for Error {}
107    /// #
108    /// # impl From<Incomplete> for Error {
109    /// #     fn from(value: Incomplete) -> Error { Error::Incomplete(value) }
110    /// # }
111    /// #
112    /// # impl From<TagStrError> for Error {
113    /// #     fn from(value: TagStrError) -> Error { Error::Tag(value) }
114    /// # }
115    /// assert_eq!(tag::<Error, _, _>("a").mapf(|_| 1).apply("a"), Ok(("", 1)));
116    /// assert_eq!(tag::<Error, _, _>("a").mapf(|(x,)| x).apply("a"), Ok(("", "a")));
117    /// ```
118    fn mapf<O2, F>(self, f: F) -> MapF<Self, F, O>
119    where
120        Self: Sized,
121        F: FnMut(O) -> O2,
122    {
123        MapF::new(self, f)
124    }
125
126    /// Maps an error `FatalError<E>` to `FatalError<E2>` by applying a function to the error.
127    ///
128    /// ```
129    /// # use pipe_chain::{tag, str::{digits, TagStrError}, MapExt, Pipe, Incomplete, EitherExt};
130    /// # use fatal_error::FatalError;
131    /// # use std::error::Error as StdError;
132    /// # #[derive(Debug, PartialEq, Eq)]
133    /// # enum Error {
134    /// #     Incomplete(Incomplete),
135    /// #     Tag(TagStrError),
136    /// # }
137    /// #
138    /// # impl std::fmt::Display for Error {
139    /// #     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
140    /// #        write!(f, "{self:?}")
141    /// #     }
142    /// # }
143    /// # impl StdError for Error {}
144    /// #
145    /// # impl From<Incomplete> for Error {
146    /// #     fn from(value: Incomplete) -> Error { Error::Incomplete(value) }
147    /// # }
148    /// #
149    /// # impl From<TagStrError> for Error {
150    /// #     fn from(value: TagStrError) -> Error { Error::Tag(value) }
151    /// # }
152    /// #[derive(Debug, PartialEq)]
153    /// struct MyError;
154    ///
155    /// assert_eq!(tag::<Error, _, _>("a").map_err(|_| FatalError::Error(MyError)).apply("b"),
156    ///            Err(FatalError::Error(MyError))
157    /// );
158    /// ```
159    fn map_err<E2, F>(self, f: F) -> MapErr<Self, F, E>
160    where
161        Self: Sized,
162        F: FnMut(FatalError<E>) -> FatalError<E2>,
163    {
164        MapErr::new(self, f)
165    }
166}
167
168impl<I, O, E, R, P> MapExt<I, O, E, R> for P where P: Pipe<I, O, E, R> {}
169
170/// [MapExt::map] implementation
171pub struct Map<P, F, O> {
172    p: P,
173    f: F,
174    o: PhantomData<O>,
175}
176
177impl<P, F, O> Map<P, F, O> {
178    fn new(p: P, f: F) -> Self { Self { p, f, o: PhantomData } }
179}
180
181impl<I, O, O2, E, R, F, P> Pipe<I, O2, E, R> for Map<P, F, O>
182where
183    O: HList,
184    F: FunMut<O, Output = O2>,
185    P: Pipe<I, O, E, R>,
186{
187    fn apply(&mut self, input: I) -> Result<R, O2, E> {
188        self.p.apply(input).map(|(i, o)| (i, self.f.call_fun_mut(o)))
189    }
190}
191
192/// [MapExt::map1] implementation
193pub struct Map1<P, F, O> {
194    p: P,
195    f: F,
196    o: PhantomData<O>,
197}
198
199impl<P, F, O> Map1<P, F, O> {
200    fn new(p: P, f: F) -> Self { Self { p, f, o: PhantomData } }
201}
202
203impl<I, O, O2, E, R, F, P> Pipe<I, (O2,), E, R> for Map1<P, F, O>
204where
205    F: FunMut<O, Output = O2>,
206    P: Pipe<I, O, E, R>,
207    O: HList,
208{
209    fn apply(&mut self, input: I) -> Result<R, (O2,), E> {
210        self.p.apply(input).map(|(i, o)| (i, (self.f.call_fun_mut(o),)))
211    }
212}
213
214/// [MapExt::mapf] implementation
215pub struct MapF<P, F, O> {
216    p: P,
217    f: F,
218    o: PhantomData<O>,
219}
220
221impl<P, F, O> MapF<P, F, O> {
222    fn new(p: P, f: F) -> Self { Self { p, f, o: PhantomData } }
223}
224
225impl<I, O, O2, E, R, F, P> Pipe<I, O2, E, R> for MapF<P, F, O>
226where
227    F: FnMut(O) -> O2,
228    P: Pipe<I, O, E, R>,
229{
230    fn apply(&mut self, input: I) -> Result<R, O2, E> {
231        self.p.apply(input).map(|(i, o)| (i, (self.f)(o)))
232    }
233}
234
235/// [MapExt::map_err] implementation
236pub struct MapErr<P, F, E> {
237    p: P,
238    f: F,
239    e: PhantomData<E>,
240}
241
242impl<P, F, E> MapErr<P, F, E> {
243    fn new(p: P, f: F) -> Self { Self { p, f, e: PhantomData } }
244}
245
246impl<I, O, E, E2, R, P, F> Pipe<I, O, E2, R> for MapErr<P, F, E>
247where
248    P: Pipe<I, O, E, R>,
249    F: FnMut(FatalError<E>) -> FatalError<E2>,
250{
251    fn apply(&mut self, input: I) -> Result<R, O, E2> {
252        self.p.apply(input).map_err(|x| (self.f)(x))
253    }
254}