map_ok/
box_ok.rs

1use crate::{MapOk, MapOkIter};
2
3/// Represents an iterator that boxes the Ok values.
4///
5/// This trait is implemented for iterators over `Result<T, E>`, allowing them to box
6/// the Ok values using the `Box<T>` type.
7///
8/// # Implementations
9///
10/// Implementations of this trait must provide an implementation for the `box_ok` function, which
11/// returns a `MapOk` iterator that boxes each Ok value encountered during iteration.
12///
13/// # Examples
14///
15/// ```
16/// use std::num::ParseIntError;
17/// use std::str::FromStr;
18/// use map_ok::{BoxOk, MapOk};
19///
20/// struct Person {
21///     age: u8,
22/// }
23///
24/// impl Person {
25///     fn new(age: u8) -> Self {
26///         Person { age }
27///     }
28/// }
29///
30/// impl FromStr for Person {
31///     type Err = ParseIntError;
32///
33///     fn from_str(s: &str) -> Result<Self, Self::Err> {
34///         let age = u8::from_str(s)?;
35///         Ok(Person::new(age))
36///     }
37/// }
38///
39/// let input = vec!["10", "20", "x", "30"];
40/// let mut iterator = input.into_iter()
41///     .map(Person::from_str)
42///     .map_ok(|p| p.age)
43///     .box_ok();
44///
45/// assert_eq!(iterator.next(), Some(Ok(Box::new(10))));
46/// assert_eq!(iterator.next(), Some(Ok(Box::new(20))));
47/// assert!(iterator.next().unwrap().is_err());
48/// assert_eq!(iterator.next(), Some(Ok(Box::new(30))));
49/// assert_eq!(iterator.next(), None);
50/// ```
51pub trait BoxOk<T, E>: Sized {
52    type Iter: Iterator<Item = Result<Box<T>, E>>;
53
54    fn box_ok(self) -> Self::Iter;
55}
56
57/// A function that boxes its argument.
58pub type BoxingFn<T> = fn(T) -> Box<T>;
59
60impl<I, T, E> BoxOk<T, E> for I
61where
62    I: Iterator<Item = Result<T, E>>,
63{
64    type Iter = MapOkIter<Self, T, E, Box<T>, BoxingFn<T>>;
65
66    fn box_ok(self) -> Self::Iter {
67        self.map_ok(Box::new)
68    }
69}
70
71#[cfg(test)]
72mod tests {
73    use std::num::ParseIntError;
74    use std::str::FromStr;
75
76    use super::*;
77
78    struct Person {
79        age: u8,
80    }
81
82    impl Person {
83        fn new(age: u8) -> Self {
84            Person { age }
85        }
86    }
87
88    impl FromStr for Person {
89        type Err = ParseIntError;
90
91        fn from_str(s: &str) -> Result<Self, Self::Err> {
92            let age = u8::from_str(s)?;
93            Ok(Person::new(age))
94        }
95    }
96
97    #[test]
98    fn map_ok_works() {
99        let input = ["10", "20", "x", "30"];
100        let mut iterator = input
101            .iter()
102            .map(|s| s.parse::<Person>())
103            .map_ok(|p| p.age)
104            .box_ok();
105
106        assert_eq!(iterator.next(), Some(Ok(Box::new(10))));
107        assert_eq!(iterator.next(), Some(Ok(Box::new(20))));
108        assert!(iterator.next().unwrap().is_err());
109        assert_eq!(iterator.next(), Some(Ok(Box::new(30))));
110        assert_eq!(iterator.next(), None);
111    }
112
113    #[test]
114    fn naive() {
115        let input = ["10", "20", "x", "30"];
116        let results: Vec<Result<Box<u32>, ParseIntError>> = input
117            .into_iter()
118            .map(u32::from_str)
119            .map_ok(|x| x * 100)
120            .box_ok()
121            .collect();
122        assert_eq!(results.len(), 4);
123    }
124
125    #[test]
126    fn naive2() {
127        let input = ["10", "20", "x", "30"];
128        let results: Vec<Result<Box<u32>, ParseIntError>> = input
129            .into_iter()
130            .map(u32::from_str)
131            .map_ok(|x| x * 100)
132            .map_ok(Box::new)
133            .collect();
134        assert_eq!(results.len(), 4);
135    }
136}