From fc206e3c9ebff3ba58dd126e380d74becffe7775 Mon Sep 17 00:00:00 2001 From: Philippe-Cholet Date: Tue, 7 Nov 2023 15:41:33 +0100 Subject: [PATCH 1/3] Refactor `IntersperseWith::next` --- src/intersperse.rs | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/intersperse.rs b/src/intersperse.rs index 035a7a3e4..1b44ed484 100644 --- a/src/intersperse.rs +++ b/src/intersperse.rs @@ -78,15 +78,20 @@ where 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.generate()) - } else { - None - } + let Self { + element, + iter, + peek, + } = self; + match peek { + item @ Some(_) => item.take(), + None => match iter.next() { + new @ Some(_) => { + *peek = new; + Some(element.generate()) + } + None => None, + }, } } From bc9738dcb974af17e8df6de20312bec32cd68fe7 Mon Sep 17 00:00:00 2001 From: Philippe-Cholet Date: Tue, 7 Nov 2023 15:44:00 +0100 Subject: [PATCH 2/3] Make `IntersperseWith` lazy Similar to what is done by `core::iter::Peekable`, a nested option is now used. --- src/intersperse.rs | 41 +++++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/src/intersperse.rs b/src/intersperse.rs index 1b44ed484..9f68a12bf 100644 --- a/src/intersperse.rs +++ b/src/intersperse.rs @@ -54,7 +54,7 @@ where { element: ElemF, iter: Fuse, - peek: Option, + peek: Option>, } /// Create a new `IntersperseWith` iterator @@ -62,10 +62,9 @@ pub fn intersperse_with(iter: I, elt: ElemF) -> IntersperseWith item.take(), - None => match iter.next() { + Some(item @ Some(_)) => item.take(), + Some(None) => match iter.next() { new @ Some(_) => { - *peek = new; + *peek = Some(new); Some(element.generate()) } None => None, }, + None => { + *peek = Some(None); + iter.next() + } } } 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) + let mut sh = self.iter.size_hint(); + sh = size_hint::add(sh, sh); + match self.peek { + Some(Some(_)) => size_hint::add_scalar(sh, 1), + Some(None) => sh, + None => size_hint::sub_scalar(sh, 1), + } } - fn fold(mut self, init: B, mut f: F) -> B + fn fold(self, init: B, mut f: F) -> B where Self: Sized, F: FnMut(B, Self::Item) -> B, { + let Self { + mut element, + mut iter, + peek, + } = self; let mut accum = init; - if let Some(x) = self.peek.take() { + if let Some(x) = peek.unwrap_or_else(|| iter.next()) { accum = f(accum, x); } - let element = &mut self.element; - - self.iter.fold(accum, |accum, x| { + iter.fold(accum, |accum, x| { let accum = f(accum, element.generate()); f(accum, x) }) From 0dd980b56c2234aeb793554c07c76d8f67c6eea4 Mon Sep 17 00:00:00 2001 From: Philippe-Cholet Date: Mon, 13 Nov 2023 18:26:45 +0100 Subject: [PATCH 3/3] Document the field `peek` of `IntersperseWith` --- src/intersperse.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/intersperse.rs b/src/intersperse.rs index 9f68a12bf..5f4f7938a 100644 --- a/src/intersperse.rs +++ b/src/intersperse.rs @@ -54,6 +54,9 @@ where { element: ElemF, iter: Fuse, + /// `peek` is None while no item have been taken out of `iter` (at definition). + /// Then `peek` will alternatively be `Some(None)` and `Some(Some(item))`, + /// where `None` indicates it's time to generate from `element` (unless `iter` is empty). peek: Option>, }