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}