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}