Skip to content

Commit

Permalink
Merge pull request #9 from CanalTP/skip_error_iter
Browse files Browse the repository at this point in the history
  • Loading branch information
Jean SIMARD authored May 12, 2021
2 parents 3039360 + 5fcd2d9 commit 1e81976
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 1 deletion.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "skip_error"
version = "1.0.1"
version = "1.1.0"
license = "MIT"
authors = ["Kisio Digital <[email protected]>"]
description = "A macro to help skip an iteration in a loop from a Result"
Expand Down
102 changes: 102 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,105 @@ macro_rules! skip_error_and_log {
}
}};
}

/// An iterator that ignore errors
pub struct SkipErrorIter<I, T, E>
where
I: Iterator<Item = Result<T, E>>,
{
inner: I,
#[cfg(feature = "log")]
log_level: Option<log::Level>,
}

impl<I, T, E> std::iter::Iterator for SkipErrorIter<I, T, E>
where
I: Iterator<Item = Result<T, E>>,
E: std::fmt::Display,
{
type Item = T;

fn next(&mut self) -> Option<Self::Item> {
self.inner.next().and_then(|result| match result {
Ok(value) => Some(value),
Err(_error) => {
#[cfg(feature = "log")]
if let Some(log_level) = self.log_level {
log::log!(log_level, "{}", _error);
}
self.next()
}
})
}
}

/// Trait to extend any [`Iterator`] where the [`Iterator::Item`] is a [`Result`].
/// This allows to skip errors and keep only the `Ok()` values.
pub trait SkipError<I, T, E>: Sized
where
I: Iterator<Item = Result<T, E>>,
{
/// Skip all errors of the [`Result`] in the original [`Iterator`].
/// This is essentially equivalent to `.flatten()`.
///
/// ```edition2018
/// use skip_error::SkipError;
/// let v: Vec<usize> = vec![0,1,0,0,3]
/// .into_iter()
/// .map(|v|
/// if v == 0 {
/// Ok(0)
/// } else {
/// Err(format!("Boom on {}", v))
/// }
/// )
/// .skip_error()
/// .collect();
/// assert_eq!(v, vec![0,0,0]);
/// ```
fn skip_error(self) -> SkipErrorIter<I, T, E>;

/// Skip all errors of the [`Result`] in the original [`Iterator`].
/// This also allows to log the errors, choosing which [`log::Level`] to use.
///
/// ```edition2018
/// use skip_error::SkipError;
/// let v: Vec<usize> = vec![0,1,0,0,3]
/// .into_iter()
/// .map(|v|
/// if v == 0 {
/// Ok(0)
/// } else {
/// Err(format!("Boom on {}", v))
/// }
/// )
/// // Will log the following messages:
/// // - WARN: Boom on 1
/// // - WARN: Boom on 3
/// .skip_error_and_log(log::Level::Warn)
/// .collect();
/// assert_eq!(v, vec![0,0,0]);
/// ```
#[cfg(feature = "log")]
fn skip_error_and_log(self, log_level: log::Level) -> SkipErrorIter<I, T, E>;
}

impl<I, T, E> SkipError<I, T, E> for I
where
I: Iterator<Item = Result<T, E>>,
{
fn skip_error(self) -> SkipErrorIter<I, T, E> {
SkipErrorIter {
inner: self,
#[cfg(feature = "log")]
log_level: None,
}
}
#[cfg(feature = "log")]
fn skip_error_and_log(self, log_level: log::Level) -> SkipErrorIter<I, T, E> {
SkipErrorIter {
inner: self,
log_level: Some(log_level),
}
}
}

0 comments on commit 1e81976

Please sign in to comment.