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}