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}