iterr/lib.rs
1/*!
2Iterator combinators to make working with iterators of `Result`s easier.
3
4## Example
5
6```rust
7extern crate iterr;
8use iterr::ItErr;
9
10fn main() {
11 let elems = vec![Ok(1i32), Ok(2), Err(3i32), Ok(4)]
12 .into_iter()
13 // This iterator's `Item` type is `Result<i32, i32>`.
14 .lift_err(|inner| inner
15 // This iterator's Item type is `i32`.
16 .map(|x| (x*2) as i64)
17 .map(|x| Ok::<i64, i32>(x))
18 )
19 .collect::<Vec<Result<i64, i32>>>();
20
21 // Note that the `Err` case cuts off the inner iterator.
22 assert_eq!(elems, vec![Ok(2i64), Ok(4), Err(3)]);
23
24 let mut trap = <_>::default(); // or: `Trap::new()`
25 // The trap is "armed" as soon as it is created.
26
27 let sum: i32 = vec![Ok(1i32), Ok(2), Err(3u8), Ok(4)]
28 .into_iter()
29 // This iterator's `Item` type is `Result<i32, u8>`.
30 .trap_err(&mut trap)
31 // This iterator's `Item` type is `i32`.
32 .sum();
33
34 // **Note**: You should avoid directly using the result of the iterator
35 // until *after* you have checked the trap.
36 assert_eq!(sum, 3);
37
38 // Convert the final value and the trap into a `Result<i32, u8>`.
39 let sum = trap.and_ok(sum);
40
41 assert_eq!(sum, Err(3));
42}
43```
44*/
45use std::cell::RefCell;
46use std::mem;
47use std::rc::Rc;
48
49/**
50Defines iterator combinators for working with iterators of `Result`s.
51*/
52pub trait ItErr: Sized + Iterator {
53 /// The iterator item's error type.
54 type ItemError;
55
56 /**
57 Lifts out just the values wrapped in `Ok` as an iterator, passing it to `wrap`, which should return another iterator.
58
59 This combinator creates a new inner iterator which yields *just* the `Ok` values of the base iterator, and passes it to the callable `wrap`. This allows the callable to consume the inner iterator without having to account for `Err` cases. Note that the inner iterator yields `None` as soon as an `Err` is encountered in the base iterator.
60
61 This callable is expected to return a new iterator whose items are `Result`s. This output iterator is then merged with the `Err` case from the base iterator.
62
63 # Example
64
65 ```rust
66 # extern crate iterr;
67 # use iterr::ItErr;
68 # fn main() {
69 let elems = vec![Ok(1i32), Ok(2), Err(3i32), Ok(4)]
70 .into_iter()
71 // This iterator's `Item` type is `Result<i32, i32>`.
72 .lift_err(|inner| inner
73 // This iterator's Item type is `i32`.
74 .map(|x| (x*2) as i64)
75 .map(|x| Ok::<i64, i32>(x))
76 )
77 .collect::<Vec<Result<i64, i32>>>();
78
79 // Note that the `Err` case cuts off the inner iterator.
80 assert_eq!(elems, vec![Ok(2i64), Ok(4), Err(3)]);
81 # }
82 ```
83 */
84 fn lift_err<Wrap, Over, U, F>(self, wrap: Wrap) -> LiftErrIter<Over::IntoIter, Self::ItemError>
85 where
86 Wrap: FnOnce(LiftTrapErrIter<Self, Self::ItemError>) -> Over,
87 Over: IntoIterator<Item=Result<U, F>>,
88 Self::ItemError: Into<F>;
89
90 /**
91 Lifts out just the values wrapped in `Ok` as an iterator, passing it to `wrap`, which should fold the iterator and return the result.
92
93 This combinator creates a new inner iterator which yields *just* the `Ok` values of the base iterator, and passes it to the callable `wrap`. This allows the callable to consume the inner iterator without having to account for `Err` cases. Note that the inner iterator yields `None` as soon as an `Err` is encountered in the base iterator.
94
95 This callable is expected to return a single `Result`. This output is then merged with the `Err` case from the base iterator.
96
97 # Example
98
99 ```rust
100 # extern crate iterr;
101 # use iterr::ItErr;
102 # fn main() {
103 let sum = vec![Ok(1i32), Ok(2), Err(3i32), Ok(4)]
104 .into_iter()
105 // This iterator's `Item` type is `Result<i32, i32>`.
106 .lift_fold_err(|inner| {
107 let v = inner
108 // This iterator's Item type is `i32`.
109 .map(|x| (x*2) as i64)
110 .sum::<i64>();
111 Ok(v)
112 });
113
114 assert_eq!(sum, Err(3));
115 # }
116 ```
117 */
118 fn lift_fold_err<Wrap, U, F>(self, wrap: Wrap) -> Result<U, F>
119 where
120 Wrap: FnOnce(LiftTrapErrIter<Self, Self::ItemError>) -> Result<U, F>,
121 Self::ItemError: Into<F>;
122
123 /**
124 Removes `Err`s from this iterator by trapping them in `trap`.
125
126 This combinator creates a new iterator which yields *just* the `Ok` values of the base iterator. If an `Err` is encountered, it is written to the given `trap`, and the iterator terminates.
127
128 It is the caller's responsibility to use the trap, whether or not an `Err` was encountered. If a `Trap` is dropped *without* being used in a debug build, a panic will be raised.
129
130 # Example
131
132 ```rust
133 # extern crate iterr;
134 # use iterr::ItErr;
135 # fn main() {
136 let mut trap = <_>::default(); // or: `Trap::new()`
137 // The trap is "armed" as soon as it is created.
138
139 let sum: i32 = vec![Ok(1i32), Ok(2), Err(3u8), Ok(4)]
140 .into_iter()
141 // This iterator's `Item` type is `Result<i32, u8>`.
142 .trap_err(&mut trap)
143 // This iterator's `Item` type is `i32`.
144 .sum();
145
146 // **Note**: You should avoid directly using the result of the iterator
147 // until *after* you have checked the trap.
148 assert_eq!(sum, 3);
149
150 // Convert the final value and the trap into a `Result<i32, u8>`.
151 let sum = trap.and_ok(sum);
152
153 assert_eq!(sum, Err(3));
154 # }
155 ```
156 */
157 fn trap_err(self, trap: &mut Trap<Self::ItemError>) -> TrapErrIter<Self, Self::ItemError>;
158
159 /**
160 Removes `Err`s from this iterator by trapping them in `trap`.
161
162 This combinator creates a new iterator which yields *just* the `Ok` values of the base iterator. If an `Err` is encountered, it is written to the given `trap`, and the iterator terminates.
163
164 It is the caller's responsibility to check the trap, whether or not an `Err` was encountered.
165
166 Unlike `trap_err`, this method uses a simple `Result<(), _>` as the trap, which may be more convenient in some cases.
167
168 **Note**: the compiler *will not* issue any warnings if the trap is not checked. Passing a mutable borrow to the `trap_err_raw` method counts as "using" it. It is recommended that you use the `trap_err` method where possible to help catch mistakes.
169
170 # Example
171
172 ```rust
173 # extern crate iterr;
174 # use iterr::ItErr;
175 # fn main() {
176 let mut trap = Ok(());
177 let sum: i32 = vec![Ok(1i32), Ok(2), Err(3u8), Ok(4)]
178 .into_iter()
179 // This iterator's `Item` type is `Result<i32, u8>`.
180 .trap_err_raw(&mut trap)
181 // This iterator's `Item` type is `i32`.
182 .sum();
183
184 // **Note**: You should avoid directly using the result of the iterator
185 // until *after* you have checked the trap.
186 assert_eq!(sum, 3);
187
188 // Convert the final value and the trap into a `Result<i32, u8>`.
189 let sum = trap.and(Ok(sum));
190
191 assert_eq!(sum, Err(3));
192 # }
193 ```
194 */
195 fn trap_err_raw(self, trap: &mut Result<(), Self::ItemError>) -> TrapErrRawIter<Self, Self::ItemError>;
196}
197
198impl<It, T, E> ItErr for It
199where It: Iterator<Item=Result<T, E>> {
200 type ItemError = E;
201
202 fn lift_err<Wrap, Over, U, F>(self, wrap: Wrap) -> LiftErrIter<Over::IntoIter, Self::ItemError>
203 where
204 Wrap: FnOnce(LiftTrapErrIter<Self, Self::ItemError>) -> Over,
205 Over: IntoIterator<Item=Result<U, F>>,
206 Self::ItemError: Into<F>,
207 {
208 let trap = Rc::new(RefCell::new(None));
209 let middle = LiftTrapErrIter {
210 iter: self,
211 trap: trap.clone(),
212 };
213 let over = wrap(middle);
214 LiftErrIter {
215 iter: Some(over.into_iter()),
216 trap: trap,
217 }
218 }
219
220 fn lift_fold_err<Wrap, U, F>(self, wrap: Wrap) -> Result<U, F>
221 where
222 Wrap: FnOnce(LiftTrapErrIter<Self, Self::ItemError>) -> Result<U, F>,
223 Self::ItemError: Into<F>,
224 {
225 let trap = Rc::new(RefCell::new(None));
226 let middle = LiftTrapErrIter {
227 iter: self,
228 trap: trap.clone(),
229 };
230 let r = wrap(middle);
231
232 if let Some(err) = trap.borrow_mut().take() {
233 return Err(err.into());
234 }
235
236 r
237 }
238
239 fn trap_err(self, trap: &mut Trap<Self::ItemError>) -> TrapErrIter<Self, Self::ItemError> {
240 TrapErrIter {
241 iter: Some(self),
242 trap: trap,
243 }
244 }
245
246 fn trap_err_raw(self, trap: &mut Result<(), Self::ItemError>) -> TrapErrRawIter<Self, Self::ItemError> {
247 TrapErrRawIter {
248 iter: Some(self),
249 trap: trap,
250 }
251 }
252}
253
254/**
255The result of the `ItErr::lift_err` combinator.
256*/
257pub struct LiftErrIter<It, Err> {
258 iter: Option<It>,
259 trap: Rc<RefCell<Option<Err>>>,
260}
261
262impl<It, Err, LiftErr, T> Iterator for LiftErrIter<It, LiftErr>
263where
264 It: Iterator<Item=Result<T, Err>>,
265 LiftErr: Into<Err>,
266{
267 type Item = Result<T, Err>;
268
269 fn next(&mut self) -> Option<Self::Item> {
270 let next = match self.iter.as_mut() {
271 Some(iter) => iter.next(),
272 None => return None,
273 };
274
275 if let Some(err) = self.trap.borrow_mut().take() {
276 self.iter = None;
277 return Some(Err(err.into()));
278 }
279
280 next
281 }
282}
283
284/**
285The inner iterator for an `ItErr::lift_err` combinator.
286*/
287pub struct LiftTrapErrIter<It, Err> {
288 iter: It,
289 trap: Rc<RefCell<Option<Err>>>,
290}
291
292impl<It, Err, T> Iterator for LiftTrapErrIter<It, Err>
293where
294 It: Iterator<Item=Result<T, Err>>,
295{
296 type Item = T;
297
298 fn next(&mut self) -> Option<Self::Item> {
299 match self.iter.next() {
300 Some(Ok(v)) => Some(v),
301 Some(Err(err)) => {
302 *self.trap.borrow_mut() = Some(err);
303 None
304 },
305 None => None,
306 }
307 }
308}
309
310/**
311A trap used for a call to `ItErr::lift_err`.
312
313Traps are "armed" unless they are consumed. If an armed trap is dropped in a debug build, a panic will be raised.
314*/
315#[must_use]
316pub struct Trap<E> {
317 armed: bool,
318 err: Result<(), E>,
319}
320
321impl<E> Trap<E> {
322 /**
323 Creates a new, empty but armed trap.
324 */
325 pub fn new() -> Self {
326 <_>::default()
327 }
328
329 /**
330 Disarms and consumes the trap, turning it into a `Result<T, E>` by combining it with another `Result<T, E>`.
331 */
332 pub fn and<T>(self, res: Result<T, E>) -> Result<T, E> {
333 match self.into_result() {
334 Ok(()) => res,
335 Err(e) => Err(e),
336 }
337 }
338
339 /**
340 Disarms and consumes the trap, turning it into a `Result<T, E>` by combining it with a value.
341 */
342 pub fn and_ok<T>(self, res: T) -> Result<T, E> {
343 match self.into_result() {
344 Ok(()) => Ok(res),
345 Err(e) => Err(e),
346 }
347 }
348
349 /**
350 Disarms and consumes the trap, turning it into a `Result<T, E>` by combining it with another `Result<T, E>`.
351
352 `op` is called *if and only if* the trap does not contain an error.
353 */
354 pub fn and_then<O, T>(self, op: O) -> Result<T, E>
355 where O: FnOnce() -> Result<T, E> {
356 match self.into_result() {
357 Ok(()) => op(),
358 Err(e) => Err(e),
359 }
360 }
361
362 /**
363 Disarms and consumes the trap, turning it into a `Result<T, E>` by combining it with a value.
364
365 `op` is called *if and only if* the trap does not contain an error.
366 */
367 pub fn and_then_ok<O, T>(self, op: O) -> Result<T, E>
368 where O: FnOnce() -> T {
369 match self.into_result() {
370 Ok(()) => Ok(op()),
371 Err(e) => Err(e),
372 }
373 }
374
375 /**
376 Disarms and consumes the trap, turning it into a `Result<(), E>`.
377
378 The result of this method should either be propogated with `?`, or combined with an `Ok(v)` using `Result::and` or `Result::and_then`.
379 */
380 pub fn into_result(mut self) -> Result<(), E> {
381 self.armed = false;
382 mem::replace(&mut self.err, Ok(()))
383 }
384}
385
386impl<E> Default for Trap<E> {
387 fn default() -> Self {
388 Trap {
389 armed: true,
390 err: Ok(()),
391 }
392 }
393}
394
395#[cfg(debug_assertions)]
396impl<E> Drop for Trap<E> {
397 fn drop(&mut self) {
398 if self.armed {
399 panic!("iterator trap was dropped before being used");
400 }
401 }
402}
403
404/**
405The result of the `ItErr::trap_err` combinator.
406*/
407pub struct TrapErrIter<'a, It, E: 'a> {
408 iter: Option<It>,
409 trap: &'a mut Trap<E>,
410}
411
412impl<'a, It, T, E> Iterator for TrapErrIter<'a, It, E>
413where It: Iterator<Item=Result<T, E>> {
414 type Item = T;
415
416 fn next(&mut self) -> Option<Self::Item> {
417 let trapped = {
418 let iter = match self.iter.as_mut() {
419 Some(iter) => iter,
420 None => return None,
421 };
422
423 match iter.next() {
424 Some(Ok(e)) => return Some(e),
425 Some(Err(err)) => Err(err),
426 None => Ok(())
427 }
428 };
429
430 self.iter = None;
431 self.trap.err = trapped;
432 None
433 }
434}
435
436/**
437The result of the `ItErr::trap_err_raw` combinator.
438*/
439pub struct TrapErrRawIter<'a, It, Trap: 'a> {
440 iter: Option<It>,
441 trap: &'a mut Result<(), Trap>,
442}
443
444impl<'a, It, T, E> Iterator for TrapErrRawIter<'a, It, E>
445where
446 It: Iterator<Item=Result<T, E>>,
447{
448 type Item = T;
449
450 fn next(&mut self) -> Option<Self::Item> {
451 let trapped = {
452 let iter = match self.iter.as_mut() {
453 Some(iter) => iter,
454 None => return None,
455 };
456
457 match iter.next() {
458 Some(Ok(e)) => return Some(e),
459 Some(Err(err)) => Err(err),
460 None => Ok(()),
461 }
462 };
463
464 self.iter = None;
465 *self.trap = trapped;
466 None
467 }
468}