From 80c9487a771b5e6642ee9bdee88b49fea07c3b81 Mon Sep 17 00:00:00 2001 From: Alexander Hirsch Date: Wed, 6 Nov 2019 16:02:51 +0100 Subject: [PATCH 1/7] Add Itertools::intersperse_with --- src/intersperse.rs | 80 +++++++++++++++++++++++++++++++++++++++++++++- src/lib.rs | 22 ++++++++++++- 2 files changed, 100 insertions(+), 2 deletions(-) diff --git a/src/intersperse.rs b/src/intersperse.rs index 057929927..a92ad99df 100644 --- a/src/intersperse.rs +++ b/src/intersperse.rs @@ -62,7 +62,7 @@ impl Iterator for Intersperse Self: Sized, F: FnMut(B, Self::Item) -> B, { let mut accum = init; - + if let Some(x) = self.peek.take() { accum = f(accum, x); } @@ -77,3 +77,81 @@ impl Iterator for Intersperse }) } } + +/// An iterator adaptor to insert a particular value created by a function +/// between each element of the adapted iterator. +/// +/// Iterator element type is `I::Item` +/// +/// This iterator is *fused*. +/// +/// See [`.intersperse_with()`](../trait.Itertools.html#method.intersperse_with) for more information. +#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] +#[derive(Debug)] +pub struct IntersperseWith + where I: Iterator, + ElemF: FnMut() -> I::Item, +{ + element: ElemF, + iter: Fuse, + peek: Option, +} + +/// Create a new IntersperseWith iterator +pub fn intersperse_with(iter: I, elt: ElemF) -> IntersperseWith + where I: Iterator, + ElemF: FnMut() -> I::Item +{ + let mut iter = iter.fuse(); + IntersperseWith { + peek: iter.next(), + iter: iter, + element: elt, + } +} + +impl Iterator for IntersperseWith + where I: Iterator, + ElemF: FnMut() -> I::Item +{ + type Item = I::Item; + #[inline] + fn next(&mut self) -> Option { + if self.peek.is_some() { + self.peek.take() + } else { + self.peek = self.iter.next(); + if self.peek.is_some() { + Some((self.element)()) + } else { + None + } + } + } + + fn size_hint(&self) -> (usize, Option) { + // 2 * SH + { 1 or 0 } + let has_peek = self.peek.is_some() as usize; + let sh = self.iter.size_hint(); + size_hint::add_scalar(size_hint::add(sh, sh), has_peek) + } + + fn fold(mut self, init: B, mut f: F) -> B where + Self: Sized, F: FnMut(B, Self::Item) -> B, + { + let mut accum = init; + + if let Some(x) = self.peek.take() { + accum = f(accum, x); + } + + let element = &mut self.element; + + self.iter.fold(accum, + |accum, x| { + let accum = f(accum, (element)()); + let accum = f(accum, x); + accum + }) + } +} diff --git a/src/lib.rs b/src/lib.rs index 0ab699e25..6e3fa187d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -107,7 +107,7 @@ pub mod structs { pub use crate::format::{Format, FormatWith}; #[cfg(feature = "use_std")] pub use crate::groupbylazy::{IntoChunks, Chunk, Chunks, GroupBy, Group, Groups}; - pub use crate::intersperse::Intersperse; + pub use crate::intersperse::{Intersperse, IntersperseWith}; #[cfg(feature = "use_std")] pub use crate::kmerge_impl::{KMerge, KMergeBy}; pub use crate::merge_join::MergeJoinBy; @@ -390,6 +390,26 @@ pub trait Itertools : Iterator { intersperse::intersperse(self, element) } + /// An iterator adaptor to insert a particular value created by a function + /// between each element of the adapted iterator. + /// + /// Iterator element type is `Self::Item`. + /// + /// This iterator is *fused*. + /// + /// ``` + /// use itertools::Itertools; + /// + /// let mut i = 10; + /// itertools::assert_equal((0..3).intersperse_with(|| { i -= 1; i }), vec![0, 9, 1, 8, 2]); + /// ``` + fn intersperse_with(self, element: F) -> IntersperseWith + where Self: Sized, + F: FnMut() -> Self::Item + { + intersperse::intersperse_with(self, element) + } + /// Create an iterator which iterates over both this and the specified /// iterator simultaneously, yielding pairs of two optional elements. /// From d55f0fb93687ddab91ec0a0979a9990eba0f28e2 Mon Sep 17 00:00:00 2001 From: Alexander Hirsch Date: Thu, 7 Nov 2019 08:57:59 +0100 Subject: [PATCH 2/7] Refine Itertools::intersperse_with doctest --- src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib.rs b/src/lib.rs index 6e3fa187d..3dc0e5649 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -402,6 +402,7 @@ pub trait Itertools : Iterator { /// /// let mut i = 10; /// itertools::assert_equal((0..3).intersperse_with(|| { i -= 1; i }), vec![0, 9, 1, 8, 2]); + /// assert_eq!(i, 8); /// ``` fn intersperse_with(self, element: F) -> IntersperseWith where Self: Sized, From 195dd1adaafc1772f9886b4e66d447a931abeadf Mon Sep 17 00:00:00 2001 From: Alexander Hirsch Date: Tue, 29 Oct 2019 13:54:14 +0100 Subject: [PATCH 3/7] Add Itertools::filter_results --- src/adaptors/mod.rs | 68 +++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 19 +++++++++++++ 2 files changed, 87 insertions(+) diff --git a/src/adaptors/mod.rs b/src/adaptors/mod.rs index 7d61f117c..700bfbc96 100644 --- a/src/adaptors/mod.rs +++ b/src/adaptors/mod.rs @@ -1124,6 +1124,74 @@ impl Iterator for MapResults } } +/// An iterator adapter to filter values within a nested `Result`. +/// +/// See [`.filter_results()`](../trait.Itertools.html#method.filter_results) for more information. +#[derive(Clone)] +#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] +pub struct FilterResults { + iter: I, + f: F +} + +/// Create a new `FilterResults` iterator. +pub fn filter_results(iter: I, f: F) -> FilterResults + where I: Iterator>, + F: FnMut(&T) -> bool, +{ + FilterResults { + iter, + f, + } +} + +impl Iterator for FilterResults + where I: Iterator>, + F: FnMut(&T) -> bool, +{ + type Item = Result; + + fn next(&mut self) -> Option { + loop { + match self.iter.next() { + Some(Ok(v)) => { + if (self.f)(&v) { + return Some(Ok(v)); + } + }, + Some(Err(e)) => return Some(Err(e)), + None => return None, + } + } + } + + fn size_hint(&self) -> (usize, Option) { + (0, self.iter.size_hint().1) + } + + fn fold(self, init: Acc, mut fold_f: Fold) -> Acc + where Fold: FnMut(Acc, Self::Item) -> Acc, + { + let mut f = self.f; + self.iter.fold(init, move |acc, v| { + if v.as_ref().map(&mut f).unwrap_or(true) { + fold_f(acc, v) + } else { + acc + } + }) + } + + fn collect(self) -> C + where C: FromIterator + { + let mut f = self.f; + self.iter.filter(move |v| { + v.as_ref().map(&mut f).unwrap_or(true) + }).collect() + } +} + /// An iterator adapter to get the positions of each element that matches a predicate. /// /// See [`.positions()`](../trait.Itertools.html#method.positions) for more information. diff --git a/src/lib.rs b/src/lib.rs index 0ab699e25..9fbdb01d4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -80,6 +80,7 @@ pub mod structs { DedupBy, Interleave, InterleaveShortest, + FilterResults, Product, PutBack, Batching, @@ -737,6 +738,24 @@ pub trait Itertools : Iterator { adaptors::map_results(self, f) } + /// Return an iterator adaptor that filters every `Result::Ok` + /// value with the provided closure. `Result::Err` values are + /// unchanged. + /// + /// ``` + /// use itertools::Itertools; + /// + /// let input = vec![Ok(22), Err(false), Ok(11)]; + /// let it = input.into_iter().filter_results(|&i| i > 20); + /// itertools::assert_equal(it, vec![Ok(22), Err(false)]); + /// ``` + fn filter_results(self, f: F) -> FilterResults + where Self: Iterator> + Sized, + F: FnMut(&T) -> bool, + { + adaptors::filter_results(self, f) + } + /// Return an iterator adaptor that merges the two base iterators in /// ascending order. If both base iterators are sorted (ascending), the /// result is sorted. From 3014ebfa0ddeb3a1a11f566ca9aef934c865669b Mon Sep 17 00:00:00 2001 From: Alexander Hirsch Date: Tue, 29 Oct 2019 13:55:53 +0100 Subject: [PATCH 4/7] Add Itertools::filter_map_results --- src/adaptors/mod.rs | 66 +++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 19 +++++++++++++ 2 files changed, 85 insertions(+) diff --git a/src/adaptors/mod.rs b/src/adaptors/mod.rs index 700bfbc96..de22a21f6 100644 --- a/src/adaptors/mod.rs +++ b/src/adaptors/mod.rs @@ -1192,6 +1192,72 @@ impl Iterator for FilterResults } } +/// An iterator adapter to filter and apply a transformation on values within a nested `Result`. +/// +/// See [`.filter_map_results()`](../trait.Itertools.html#method.filter_map_results) for more information. +#[derive(Clone)] +#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] +pub struct FilterMapResults { + iter: I, + f: F +} + +/// Create a new `FilterResults` iterator. +pub fn filter_map_results(iter: I, f: F) -> FilterMapResults + where I: Iterator>, + F: FnMut(T) -> Option, +{ + FilterMapResults { + iter, + f, + } +} + +impl Iterator for FilterMapResults + where I: Iterator>, + F: FnMut(T) -> Option, +{ + type Item = Result; + + fn next(&mut self) -> Option { + loop { + match self.iter.next() { + Some(Ok(v)) => { + if let Some(v) = (self.f)(v) { + return Some(Ok(v)); + } + }, + Some(Err(e)) => return Some(Err(e)), + None => return None, + } + } + } + + fn size_hint(&self) -> (usize, Option) { + (0, self.iter.size_hint().1) + } + + fn fold(self, init: Acc, mut fold_f: Fold) -> Acc + where Fold: FnMut(Acc, Self::Item) -> Acc, + { + let mut f = self.f; + self.iter.fold(init, move |acc, v| { + if let Some(v) = v.map(&mut f).transpose() { + fold_f(acc, v) + } else { + acc + } + }) + } + + fn collect(self) -> C + where C: FromIterator + { + let mut f = self.f; + self.iter.filter_map(move |v| v.map(&mut f).transpose()).collect() + } +} + /// An iterator adapter to get the positions of each element that matches a predicate. /// /// See [`.positions()`](../trait.Itertools.html#method.positions) for more information. diff --git a/src/lib.rs b/src/lib.rs index 9fbdb01d4..5c3b7ded4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -80,6 +80,7 @@ pub mod structs { DedupBy, Interleave, InterleaveShortest, + FilterMapResults, FilterResults, Product, PutBack, @@ -756,6 +757,24 @@ pub trait Itertools : Iterator { adaptors::filter_results(self, f) } + /// Return an iterator adaptor that filters and transforms every + /// `Result::Ok` value with the provided closure. `Result::Err` + /// values are unchanged. + /// + /// ``` + /// use itertools::Itertools; + /// + /// let input = vec![Ok(22), Err(false), Ok(11)]; + /// let it = input.into_iter().filter_map_results(|i| if i > 20 { Some(i * 2) } else { None }); + /// itertools::assert_equal(it, vec![Ok(44), Err(false)]); + /// ``` + fn filter_map_results(self, f: F) -> FilterMapResults + where Self: Iterator> + Sized, + F: FnMut(T) -> Option, + { + adaptors::filter_map_results(self, f) + } + /// Return an iterator adaptor that merges the two base iterators in /// ascending order. If both base iterators are sorted (ascending), the /// result is sorted. From 20abbbcb224afefedd8c841e01db6eac99692fc1 Mon Sep 17 00:00:00 2001 From: Alexander Hirsch Date: Fri, 13 Mar 2020 17:00:23 +0100 Subject: [PATCH 5/7] Refactor FilterResults and FilterMapResults Also remove calls to Result::transpose() to stay compatible to Rust 1.24. --- src/adaptors/mod.rs | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/src/adaptors/mod.rs b/src/adaptors/mod.rs index de22a21f6..29b7ca133 100644 --- a/src/adaptors/mod.rs +++ b/src/adaptors/mod.rs @@ -1169,24 +1169,20 @@ impl Iterator for FilterResults (0, self.iter.size_hint().1) } - fn fold(self, init: Acc, mut fold_f: Fold) -> Acc + fn fold(self, init: Acc, fold_f: Fold) -> Acc where Fold: FnMut(Acc, Self::Item) -> Acc, { let mut f = self.f; - self.iter.fold(init, move |acc, v| { - if v.as_ref().map(&mut f).unwrap_or(true) { - fold_f(acc, v) - } else { - acc - } - }) + self.iter.filter(|v| { + v.as_ref().map(&mut f).unwrap_or(true) + }).fold(init, fold_f) } fn collect(self) -> C where C: FromIterator { let mut f = self.f; - self.iter.filter(move |v| { + self.iter.filter(|v| { v.as_ref().map(&mut f).unwrap_or(true) }).collect() } @@ -1202,6 +1198,14 @@ pub struct FilterMapResults { f: F } +fn transpose_result(result: Result, E>) -> Option> { + match result { + Ok(Some(v)) => Some(Ok(v)), + Ok(None) => None, + Err(e) => Some(Err(e)), + } +} + /// Create a new `FilterResults` iterator. pub fn filter_map_results(iter: I, f: F) -> FilterMapResults where I: Iterator>, @@ -1237,24 +1241,22 @@ impl Iterator for FilterMapResults (0, self.iter.size_hint().1) } - fn fold(self, init: Acc, mut fold_f: Fold) -> Acc + fn fold(self, init: Acc, fold_f: Fold) -> Acc where Fold: FnMut(Acc, Self::Item) -> Acc, { let mut f = self.f; - self.iter.fold(init, move |acc, v| { - if let Some(v) = v.map(&mut f).transpose() { - fold_f(acc, v) - } else { - acc - } - }) + self.iter.filter_map(|v| { + transpose_result(v.map(&mut f)) + }).fold(init, fold_f) } fn collect(self) -> C where C: FromIterator { let mut f = self.f; - self.iter.filter_map(move |v| v.map(&mut f).transpose()).collect() + self.iter.filter_map(|v| { + transpose_result(v.map(&mut f)) + }).collect() } } From 3890a930e6151ec29bdfe8082e20b6cf6296bcd6 Mon Sep 17 00:00:00 2001 From: Alexander Hirsch Date: Mon, 23 Mar 2020 18:00:22 +0100 Subject: [PATCH 6/7] Rename .*_results() -> .*_ok() --- src/adaptors/mod.rs | 46 +++++++++++++++++++++++--------------------- src/lib.rs | 47 ++++++++++++++++++++++++++++++--------------- 2 files changed, 56 insertions(+), 37 deletions(-) diff --git a/src/adaptors/mod.rs b/src/adaptors/mod.rs index 29b7ca133..c9b445e0a 100644 --- a/src/adaptors/mod.rs +++ b/src/adaptors/mod.rs @@ -1074,28 +1074,31 @@ where I::Item: Into, {} -/// An iterator adapter to apply a transformation within a nested `Result`. +#[deprecated(note="Use MapOk instead", since="0.10")] +pub type MapResults = MapOk; + +/// An iterator adapter to apply a transformation within a nested `Result::Ok`. /// -/// See [`.map_results()`](../trait.Itertools.html#method.map_results) for more information. +/// See [`.map_ok()`](../trait.Itertools.html#method.map_ok) for more information. #[derive(Clone)] #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct MapResults { +pub struct MapOk { iter: I, f: F } -/// Create a new `MapResults` iterator. -pub fn map_results(iter: I, f: F) -> MapResults +/// Create a new `MapOk` iterator. +pub fn map_ok(iter: I, f: F) -> MapOk where I: Iterator>, F: FnMut(T) -> U, { - MapResults { + MapOk { iter, f, } } -impl Iterator for MapResults +impl Iterator for MapOk where I: Iterator>, F: FnMut(T) -> U, { @@ -1124,28 +1127,28 @@ impl Iterator for MapResults } } -/// An iterator adapter to filter values within a nested `Result`. +/// An iterator adapter to filter values within a nested `Result::Ok`. /// -/// See [`.filter_results()`](../trait.Itertools.html#method.filter_results) for more information. +/// See [`.filter_ok()`](../trait.Itertools.html#method.filter_ok) for more information. #[derive(Clone)] #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct FilterResults { +pub struct FilterOk { iter: I, f: F } -/// Create a new `FilterResults` iterator. -pub fn filter_results(iter: I, f: F) -> FilterResults +/// Create a new `FilterOk` iterator. +pub fn filter_ok(iter: I, f: F) -> FilterOk where I: Iterator>, F: FnMut(&T) -> bool, { - FilterResults { + FilterOk { iter, f, } } -impl Iterator for FilterResults +impl Iterator for FilterOk where I: Iterator>, F: FnMut(&T) -> bool, { @@ -1188,12 +1191,11 @@ impl Iterator for FilterResults } } -/// An iterator adapter to filter and apply a transformation on values within a nested `Result`. +/// An iterator adapter to filter and apply a transformation on values within a nested `Result::Ok`. /// -/// See [`.filter_map_results()`](../trait.Itertools.html#method.filter_map_results) for more information. -#[derive(Clone)] +/// See [`.filter_map_ok()`](../trait.Itertools.html#method.filter_map_ok) for more information. #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct FilterMapResults { +pub struct FilterMapOk { iter: I, f: F } @@ -1206,18 +1208,18 @@ fn transpose_result(result: Result, E>) -> Option> } } -/// Create a new `FilterResults` iterator. -pub fn filter_map_results(iter: I, f: F) -> FilterMapResults +/// Create a new `FilterOk` iterator. +pub fn filter_map_ok(iter: I, f: F) -> FilterMapOk where I: Iterator>, F: FnMut(T) -> Option, { - FilterMapResults { + FilterMapOk { iter, f, } } -impl Iterator for FilterMapResults +impl Iterator for FilterMapOk where I: Iterator>, F: FnMut(T) -> Option, { diff --git a/src/lib.rs b/src/lib.rs index 5c3b7ded4..20cb4f4de 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -80,12 +80,13 @@ pub mod structs { DedupBy, Interleave, InterleaveShortest, - FilterMapResults, - FilterResults, + FilterMapOk, + FilterOk, Product, PutBack, Batching, MapInto, + MapOk, MapResults, Merge, MergeBy, @@ -721,6 +722,14 @@ pub trait Itertools : Iterator { adaptors::map_into(self) } + #[deprecated(note="Use .map_ok() instead", since="0.10")] + fn map_results(self, f: F) -> MapOk + where Self: Iterator> + Sized, + F: FnMut(T) -> U, + { + self.map_ok(f) + } + /// Return an iterator adaptor that applies the provided closure /// to every `Result::Ok` value. `Result::Err` values are /// unchanged. @@ -729,14 +738,14 @@ pub trait Itertools : Iterator { /// use itertools::Itertools; /// /// let input = vec![Ok(41), Err(false), Ok(11)]; - /// let it = input.into_iter().map_results(|i| i + 1); + /// let it = input.into_iter().map_ok(|i| i + 1); /// itertools::assert_equal(it, vec![Ok(42), Err(false), Ok(12)]); /// ``` - fn map_results(self, f: F) -> MapResults + fn map_ok(self, f: F) -> MapOk where Self: Iterator> + Sized, F: FnMut(T) -> U, { - adaptors::map_results(self, f) + adaptors::map_ok(self, f) } /// Return an iterator adaptor that filters every `Result::Ok` @@ -747,14 +756,14 @@ pub trait Itertools : Iterator { /// use itertools::Itertools; /// /// let input = vec![Ok(22), Err(false), Ok(11)]; - /// let it = input.into_iter().filter_results(|&i| i > 20); + /// let it = input.into_iter().filter_ok(|&i| i > 20); /// itertools::assert_equal(it, vec![Ok(22), Err(false)]); /// ``` - fn filter_results(self, f: F) -> FilterResults + fn filter_ok(self, f: F) -> FilterOk where Self: Iterator> + Sized, F: FnMut(&T) -> bool, { - adaptors::filter_results(self, f) + adaptors::filter_ok(self, f) } /// Return an iterator adaptor that filters and transforms every @@ -765,14 +774,14 @@ pub trait Itertools : Iterator { /// use itertools::Itertools; /// /// let input = vec![Ok(22), Err(false), Ok(11)]; - /// let it = input.into_iter().filter_map_results(|i| if i > 20 { Some(i * 2) } else { None }); + /// let it = input.into_iter().filter_map_ok(|i| if i > 20 { Some(i * 2) } else { None }); /// itertools::assert_equal(it, vec![Ok(44), Err(false)]); /// ``` - fn filter_map_results(self, f: F) -> FilterMapResults + fn filter_map_ok(self, f: F) -> FilterMapOk where Self: Iterator> + Sized, F: FnMut(T) -> Option, { - adaptors::filter_map_results(self, f) + adaptors::filter_map_ok(self, f) } /// Return an iterator adaptor that merges the two base iterators in @@ -1761,6 +1770,14 @@ pub trait Itertools : Iterator { format::new_format(self, sep, format) } + #[deprecated(note="Use .fold_ok() instead", since="0.10")] + fn fold_results(&mut self, mut start: B, mut f: F) -> Result + where Self: Iterator>, + F: FnMut(B, A) -> B + { + self.fold_ok(start, f) + } + /// Fold `Result` values from an iterator. /// /// Only `Ok` values are folded. If no error is encountered, the folded @@ -1793,17 +1810,17 @@ pub trait Itertools : Iterator { /// assert_eq!( /// values.iter() /// .map(Ok::<_, ()>) - /// .fold_results(0, Add::add), + /// .fold_ok(0, Add::add), /// Ok(3) /// ); /// assert!( /// values.iter() /// .map(|&x| if x >= 0 { Ok(x) } else { Err("Negative number") }) - /// .fold_results(0, Add::add) + /// .fold_ok(0, Add::add) /// .is_err() /// ); /// ``` - fn fold_results(&mut self, mut start: B, mut f: F) -> Result + fn fold_ok(&mut self, mut start: B, mut f: F) -> Result where Self: Iterator>, F: FnMut(B, A) -> B { @@ -1822,7 +1839,7 @@ pub trait Itertools : Iterator { /// value is returned inside `Some`. Otherwise, the operation terminates /// and returns `None`. No iterator elements are consumed after the `None`. /// - /// This is the `Option` equivalent to `fold_results`. + /// This is the `Option` equivalent to `fold_ok`. /// /// ``` /// use std::ops::Add; From 22b19842abb82cb7841ec367ec0917693a889f04 Mon Sep 17 00:00:00 2001 From: Alexander Hirsch Date: Tue, 5 May 2020 09:44:26 +0200 Subject: [PATCH 7/7] Derive Clone for IntersperseWith --- src/intersperse.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/intersperse.rs b/src/intersperse.rs index a92ad99df..4cd2fa5a8 100644 --- a/src/intersperse.rs +++ b/src/intersperse.rs @@ -1,7 +1,6 @@ use std::iter::Fuse; use super::size_hint; -#[derive(Clone)] /// An iterator adaptor to insert a particular value /// between each element of the adapted iterator. /// @@ -11,7 +10,7 @@ use super::size_hint; /// /// See [`.intersperse()`](../trait.Itertools.html#method.intersperse) for more information. #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -#[derive(Debug)] +#[derive(Clone, Debug)] pub struct Intersperse where I: Iterator { @@ -87,7 +86,7 @@ impl Iterator for Intersperse /// /// See [`.intersperse_with()`](../trait.Itertools.html#method.intersperse_with) for more information. #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -#[derive(Debug)] +#[derive(Clone, Debug)] pub struct IntersperseWith where I: Iterator, ElemF: FnMut() -> I::Item,