diff --git a/src/lib.rs b/src/lib.rs index c8422f531..c4669d75a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -133,6 +133,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; @@ -222,6 +223,7 @@ mod tuple_impl; mod unique_impl; mod unziptuple; mod with_position; +mod with_prev; mod zip_eq_impl; mod zip_longest; mod ziptuple; @@ -1804,6 +1806,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..33ee490c4 --- /dev/null +++ b/src/with_prev.rs @@ -0,0 +1,41 @@ +/// 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 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 = std::mem::replace(&mut self.prev, Some(next.clone())); + Some((prev, next)) + } +}