diff --git a/src/lib.rs b/src/lib.rs index 804c7c450..6519a0ddb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -147,6 +147,7 @@ pub mod structs { #[cfg(feature = "use_std")] pub use crate::unique_impl::{Unique, UniqueBy}; pub use crate::with_position::WithPosition; + pub use crate::with_prev::WithPrev; pub use crate::zip_eq_impl::ZipEq; pub use crate::zip_longest::ZipLongest; pub use crate::ziptuple::Zip; @@ -243,6 +244,7 @@ mod tuple_impl; mod unique_impl; mod unziptuple; mod with_position; +mod with_prev; mod zip_eq_impl; mod zip_longest; mod ziptuple; @@ -2247,6 +2249,26 @@ pub trait Itertools: Iterator { with_position::with_position(self) } + /// Return an iterator adaptor that combines each element except the first with + /// a clone of the previous. + /// + /// ``` + /// use itertools::Itertools; + /// + /// let it = (0..4).with_prev(); + /// itertools::assert_equal(it, + /// vec![(None, 0), + /// (Some(0), 1), + /// (Some(1), 2), + /// (Some(2), 3)]); + /// ``` + fn with_prev(self) -> WithPrev + where + Self: Sized, + { + with_prev::with_prev(self) + } + /// Return an iterator adaptor that yields the indices of all elements /// satisfying a predicate, counted from the start of the iterator. /// diff --git a/src/with_prev.rs b/src/with_prev.rs new file mode 100644 index 000000000..b95ace8c3 --- /dev/null +++ b/src/with_prev.rs @@ -0,0 +1,51 @@ +use std::fmt; + +/// An iterator adaptor that combines each element except the first with a clone of the previous. +/// +/// See [`.with_prev()`](crate::Itertools::with_prev) for more information. +#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] +pub struct WithPrev +where + I: Iterator, +{ + iter: I, + prev: Option, +} + +impl fmt::Debug for WithPrev +where + I: Iterator + fmt::Debug, + I::Item: fmt::Debug, +{ + debug_fmt_fields!(WithPrev, prev, iter); +} + +impl Clone for WithPrev +where + I: Clone + Iterator, + I::Item: Clone, +{ + clone_fields!(iter, prev); +} + +/// Create a new `WithPrev` iterator. +pub fn with_prev(iter: I) -> WithPrev +where + I: Iterator, +{ + WithPrev { iter, prev: None } +} + +impl Iterator for WithPrev +where + I: Iterator, + I::Item: Clone, +{ + type Item = (Option, I::Item); + + fn next(&mut self) -> Option { + let next = self.iter.next()?; + let prev = self.prev.replace(next.clone()); + Some((prev, next)) + } +}