FirstErr

Trait FirstErr 

Source
pub trait FirstErr: Iterator {
    // Provided methods
    fn first_err_or_else<T, E, O, F>(self, f: F) -> Result<O, E>
       where F: FnOnce(&mut FirstErrIter<Self, T, E>) -> O,
             Self: Iterator<Item = Result<T, E>> + Sized { ... }
    fn first_err_or_try<T, E, O, F>(self, f: F) -> Result<O, E>
       where F: FnOnce(&mut FirstErrIter<Self, T, E>) -> Result<O, E>,
             Self: Iterator<Item = Result<T, E>> + Sized { ... }
    fn first_err_or<T, E, O>(self, value: O) -> Result<O, E>
       where Self: Iterator<Item = Result<T, E>> + Sized { ... }
    fn first_none_or_else<T, O, F>(self, f: F) -> Option<O>
       where F: FnOnce(&mut FirstNoneIter<Self, T>) -> O,
             Self: Iterator<Item = Option<T>> + Sized { ... }
    fn first_none_or_try<T, O, F>(self, f: F) -> Option<O>
       where F: FnOnce(&mut FirstNoneIter<Self, T>) -> Option<O>,
             Self: Iterator<Item = Option<T>> + Sized { ... }
    fn first_none_or<T, O>(self, value: O) -> Option<O>
       where Self: Iterator<Item = Option<T>> + Sized { ... }
}
Expand description

This trait provides some methods on any Iterator<Item = Result<T, E>>, which can take the first Err in iterators, and without allocation.

Iterator<Item = Option<T>> version with the same logic are also supported.

§Guarantees

There are some methods in FirstErr trait take a closure that accepts an iterator as its argument. This crate guarantees all those methods have the following properties.

§Original Iterator is Evaluated Lazily

The .next() of the original iterator only be called as late as possible, For example,

let mut vec = RefCell::new(vec![]);

let mut result = [Ok::<u8, u8>(0), Ok(1), Err(2), Ok(3)]
    .into_iter()
    .inspect(|res| { vec.borrow_mut().push(*res) })         // push value from outer
    .first_err_or_else(|iter| {
        iter
            .inspect(|n| { vec.borrow_mut().push(Ok(42)) }) // push value from inner
            .sum::<u8>()
    });

assert_eq!(result, Err(2));
assert_eq!(
    vec.into_inner(),
    vec![Ok(0), Ok(42), Ok(1), Ok(42), Err(2)],
);

§No Need to Manually Consume the Closure’s Iterator

User can simple ignore the iterator in closure partially of fully, and still can get the correct result.

let result = [Ok::<u8, u8>(0), Err(1), Err(2)]
    .into_iter()
    .first_err_or_else(|_iter| {}); // not need to consume `_iter` iterator,
assert_eq!(result, Err(1));         // and the result still correct.

§Iterator in Closure Can’t be Leaked Out of Closure Scope

Let the iterator in closure escaped from the closure is a compiler error.

let iter = [Ok::<u8, u8>(0), Err(1), Err(2)]
    .into_iter()
    .first_err_or_else(|iter| iter); // compile error: can't leak `iter` out

Provided Methods§

Source

fn first_err_or_else<T, E, O, F>(self, f: F) -> Result<O, E>
where F: FnOnce(&mut FirstErrIter<Self, T, E>) -> O, Self: Iterator<Item = Result<T, E>> + Sized,

Returns the first Err item in the current iterator, or an Ok value produced by the f closure.

The argument iterator of the f closure will producing the same values in Ok sequence, but will stop when encounter the first Err item.

§Examples
use first_err::FirstErr;

// Everything is Ok.
let result = [Ok::<u8, u8>(0), Ok(1), Ok(2)]
    .into_iter()
    .first_err_or_else(|iter| iter.sum::<u8>());
assert_eq!(result, Ok(3));

// Contains some `Err` values.
let result = [Ok::<u8, u8>(0), Err(1), Err(2)]
    .into_iter()
    .first_err_or_else(|iter| iter.sum::<u8>());
assert_eq!(result, Err(1));
Source

fn first_err_or_try<T, E, O, F>(self, f: F) -> Result<O, E>
where F: FnOnce(&mut FirstErrIter<Self, T, E>) -> Result<O, E>, Self: Iterator<Item = Result<T, E>> + Sized,

Returns the first Err item in the current iterator, or an Result value produced by the f closure.

The argument iterator of the f closure will producing the same values in Ok sequence, but will stop when encounter the first Err item.

§Examples

Basic concept:

use first_err::FirstErr;

// Everything is Ok.
let result = [Ok::<u8, u8>(0), Ok(1), Ok(2)]
    .into_iter()
    .first_err_or_try(|_| Ok("ok"));
assert_eq!(result, Ok("ok"));

// When closure returns Err.
let result = [Ok::<u8, u8>(0), Ok(1), Ok(2)]
    .into_iter()
    .first_err_or_try(|_| Err::<u8, u8>(42));
assert_eq!(result, Err(42));

// When outer iterator contains Err.
let result = [Ok::<u8, u8>(0), Err(2), Ok(2)]
    .into_iter()
    .first_err_or_try(|_| Ok("ok"));
assert_eq!(result, Err(2));

// When both contains Err.
let result = [Ok::<u8, u8>(0), Err(1), Ok(2)]
    .into_iter()
    .first_err_or_try(|_| Err::<u8, u8>(42));
assert_eq!(result, Err(1));

Use the iter argument of the f closure:

let admin_id: u32 = 1;
let user_ids_in_conf = ["32", "5", "8", "19"];

let admin_index = user_ids_in_conf
    .into_iter()
    .map(|s| s.parse::<u32>().map_err(|_| "user id parsing failed"))
    .first_err_or_try(|user_ids_iter| {
        user_ids_iter
            .position(|user_id| user_id == admin_id)
            .ok_or_else(|| "admin not in the user list")
    });

assert_eq!(admin_index, Err("admin not in the user list"));
Source

fn first_err_or<T, E, O>(self, value: O) -> Result<O, E>
where Self: Iterator<Item = Result<T, E>> + Sized,

Returns the first Err item in the current iterator, or an Ok(value).

§Examples
// Everything is Ok.
let result = [Ok::<u8, u8>(0), Ok(1), Ok(2)]
    .into_iter()
    .first_err_or("foo");
assert_eq!(result, Ok("foo"));

// Contains some `Err` values.
let result = [Ok::<u8, u8>(0), Err(1), Err(2)]
    .into_iter()
    .first_err_or("foo");
assert_eq!(result, Err(1));
Source

fn first_none_or_else<T, O, F>(self, f: F) -> Option<O>
where F: FnOnce(&mut FirstNoneIter<Self, T>) -> O, Self: Iterator<Item = Option<T>> + Sized,

Returns the first None item in the current iterator, or an Some value produced by the f closure.

The argument iterator of the f closure will producing the same values in Some sequence, but will stop when encounter the first None item.

§Examples
use first_err::FirstErr;

// Everything is Some.
let option = [Some::<u8>(0), Some(1), Some(2)]
    .into_iter()
    .first_none_or_else(|iter| iter.sum::<u8>());
assert_eq!(option, Some(3));

// Contains some `None` values.
let option = [Some::<u8>(0), None, None]
    .into_iter()
    .first_none_or_else(|iter| iter.sum::<u8>());
assert_eq!(option, None);
Source

fn first_none_or_try<T, O, F>(self, f: F) -> Option<O>
where F: FnOnce(&mut FirstNoneIter<Self, T>) -> Option<O>, Self: Iterator<Item = Option<T>> + Sized,

Returns the first None item in the current iterator, or an Option value produced by the f closure.

The argument iterator of the f closure will producing the same values in Some sequence, but will stop when encounter the first None item.

§Examples

Basic concept:

use first_err::FirstErr;

// Everything is Some.
let option = [Some::<u8>(0), Some(1), Some(2)]
    .into_iter()
    .first_none_or_try(|_| Some("ok"));
assert_eq!(option, Some("ok"));

// When closure returns None.
let option: Option<&str> = [Some::<u8>(0), Some(1), Some(2)]
    .into_iter()
    .first_none_or_try(|_| None);
assert_eq!(option, None);

// When outer iterator contains None.
let option = [Some::<u8>(0), None, Some(2)]
    .into_iter()
    .first_none_or_try(|_| Some("ok"));
assert_eq!(option, None);

// When both contains None.
let option: Option<&str> = [Some::<u8>(0), None, Some(2)]
    .into_iter()
    .first_none_or_try(|_| None);
assert_eq!(option, None);

Use the iter argument of the f closure:

let admin_id: u32 = 1;
let user_ids_in_conf = ["32", "5", "8", "19"];

let admin_index = user_ids_in_conf
    .into_iter()
    .map(|s| s.parse::<u32>().ok())
    .first_none_or_try(|user_ids_iter| {
        user_ids_iter
            .position(|user_id| user_id == admin_id)
    });

assert_eq!(admin_index, None);
Source

fn first_none_or<T, O>(self, value: O) -> Option<O>
where Self: Iterator<Item = Option<T>> + Sized,

Returns the first None item in the current iterator, or an Some(value).

§Examples
// Everything is Some.
let option = [Some::<u8>(0), Some(1), Some(2)]
    .into_iter()
    .first_none_or("foo");
assert_eq!(option, Some("foo"));

// Contains some `None` values.
let option = [Some::<u8>(0), None, None]
    .into_iter()
    .first_none_or("foo");
assert_eq!(option, None);

Implementors§

Source§

impl<I> FirstErr for I
where I: Iterator,