map_ok/
map_ok.rs

1use std::marker::PhantomData;
2
3/// Represents an iterator that maps the Ok values to another type using the given function.
4///
5/// This trait is implemented for iterators over `Result<T, E>`, allowing them to transform
6/// the Ok values using a closure.
7///
8/// # Example
9///
10/// ```
11/// use std::iter::Iterator;
12/// use map_ok::MapOkIter;
13///
14/// pub trait MapOk<T, E>: Sized {
15///     fn map_ok<U, F>(self, f: F) -> MapOkIter<Self, T, E, U, F>
16///     where
17///         F: Fn(T) -> U;
18/// }
19/// ```
20///
21/// # Implementations
22///
23/// Implementations of this trait must provide an implementation for the `map_ok` function, which receives
24/// a closure `f` that takes an Ok value of type `T` and returns a value of type `U`. It returns a `MapOk`
25/// iterator, which will apply the closure to each Ok value encountered during iteration.
26pub trait MapOk<T, E, F, U>: Sized
27where
28    F: Fn(T) -> U,
29{
30    type Iter: Iterator<Item = Result<U, E>>;
31
32    fn map_ok(self, f: F) -> Self::Iter;
33}
34
35impl<I, T, E, U, F> MapOk<T, E, F, U> for I
36where
37    I: Iterator<Item = Result<T, E>>,
38    F: Fn(T) -> U,
39{
40    type Iter = MapOkIter<Self, T, E, U, F>;
41
42    fn map_ok(self, f: F) -> Self::Iter {
43        MapOkIter {
44            iter: self,
45            f,
46            _phantom: PhantomData,
47        }
48    }
49}
50
51/// A special iterator adapter that applies a function to the elements of an underlying iterator,
52/// similar to `Iterator::map`, but returns `Ok` variant of the result.
53///
54/// # Type arguments
55/// * `I` - The iterator itself.
56/// * `T` - The type of [`Ok`] variant of the iterated item.
57/// * `E` - The type of the [`Err`] variant of the iterated item.
58/// * `U` - The mapped type.
59/// * `F` - A [`Fn`] that maps from `T` to `U`.
60///
61/// # Examples
62///
63/// ```
64/// use std::num::ParseIntError;
65/// use std::str::FromStr;
66/// use map_ok::MapOk;
67///
68/// struct Person {
69///     age: u8,
70/// }
71///
72/// impl Person {
73///     fn new(age: u8) -> Self {
74///         Person { age }
75///     }
76/// }
77///
78/// impl FromStr for Person {
79///     type Err = ParseIntError;
80///
81///     fn from_str(s: &str) -> Result<Self, Self::Err> {
82///         let age = u8::from_str(s)?;
83///         Ok(Person::new(age))
84///     }
85/// }
86///
87/// let input = vec!["10", "20", "x", "30"];
88/// let mut iterator = input.iter()
89///     .map(|s| s.parse::<Person>())
90///     .map_ok(|p| p.age);
91///
92/// assert_eq!(iterator.next(), Some(Ok(10)));
93/// assert_eq!(iterator.next(), Some(Ok(20)));
94/// assert!(iterator.next().unwrap().is_err());
95/// assert_eq!(iterator.next(), Some(Ok(30)));
96/// assert_eq!(iterator.next(), None);
97/// ```
98pub struct MapOkIter<I, T, E, U, F> {
99    iter: I,
100    f: F,
101    _phantom: PhantomData<MapFn<T, E, U>>,
102}
103
104/// Helper type to simplify type definition.
105type MapFn<T, E, U> = fn(T, E) -> (U, Result<T, E>);
106
107impl<I, T, E, U, F> Iterator for MapOkIter<I, T, E, U, F>
108where
109    I: Iterator<Item = Result<T, E>>,
110    F: FnMut(T) -> U,
111{
112    type Item = Result<U, E>;
113
114    fn next(&mut self) -> Option<Self::Item> {
115        match self.iter.next() {
116            Some(Ok(value)) => Some(Ok((self.f)(value))),
117            Some(Err(e)) => Some(Err(e)),
118            None => None,
119        }
120    }
121}
122
123#[cfg(test)]
124mod tests {
125    use std::num::ParseIntError;
126    use std::str::FromStr;
127
128    use super::*;
129
130    struct Person {
131        age: u8,
132    }
133
134    impl Person {
135        fn new(age: u8) -> Self {
136            Person { age }
137        }
138    }
139
140    impl FromStr for Person {
141        type Err = ParseIntError;
142
143        fn from_str(s: &str) -> Result<Self, Self::Err> {
144            let age = u8::from_str(s)?;
145            Ok(Person::new(age))
146        }
147    }
148
149    #[test]
150    fn map_ok_works() {
151        let input = ["10", "20", "x", "30"];
152        let mut iterator = input.into_iter().map(Person::from_str).map_ok(|p| p.age);
153
154        assert_eq!(iterator.next(), Some(Ok(10)));
155        assert_eq!(iterator.next(), Some(Ok(20)));
156        assert!(iterator.next().unwrap().is_err());
157        assert_eq!(iterator.next(), Some(Ok(30)));
158        assert_eq!(iterator.next(), None);
159    }
160
161    #[test]
162    fn naive() {
163        let input = ["10", "20", "x", "30"];
164        let mut iterator = input.into_iter().map(u32::from_str).map(|p| match p {
165            Ok(p) => Ok(p * 100),
166            Err(e) => Err(e),
167        });
168
169        assert_eq!(iterator.next(), Some(Ok(1000)));
170        assert_eq!(iterator.next(), Some(Ok(2000)));
171        assert!(iterator.next().unwrap().is_err());
172        assert_eq!(iterator.next(), Some(Ok(3000)));
173        assert_eq!(iterator.next(), None);
174    }
175}