From 11ca7914824850459164b195774d2b56521104ba Mon Sep 17 00:00:00 2001 From: Erik Rhodes Date: Mon, 23 May 2022 15:43:38 -0600 Subject: [PATCH 1/7] added take_until adaptor and doctests --- src/lib.rs | 81 +++++++++++++++++++++++++++++++++++++---------- src/take_until.rs | 54 +++++++++++++++++++++++++++++++ 2 files changed, 119 insertions(+), 16 deletions(-) create mode 100644 src/take_until.rs diff --git a/src/lib.rs b/src/lib.rs index 6e86ab789..364409ae0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -146,6 +146,7 @@ pub mod structs { pub use crate::repeatn::RepeatN; #[allow(deprecated)] pub use crate::sources::{RepeatCall, Unfold, Iterate}; + pub use crate::take_until::TakeUntil; #[cfg(feature = "use_alloc")] pub use crate::tee::Tee; pub use crate::tuple_impl::{TupleBuffer, TupleWindows, CircularTupleWindows, Tuples}; @@ -233,6 +234,7 @@ mod rciter_impl; mod repeatn; mod size_hint; mod sources; +mod take_until; #[cfg(feature = "use_alloc")] mod tee; mod tuple_impl; @@ -904,7 +906,7 @@ pub trait Itertools : Iterator { /// Return an iterator adaptor that flattens every `Result::Ok` value into /// a series of `Result::Ok` values. `Result::Err` values are unchanged. - /// + /// /// This is useful when you have some common error type for your crate and /// need to propagate it upwards, but the `Result::Ok` case needs to be flattened. /// @@ -914,7 +916,7 @@ pub trait Itertools : Iterator { /// let input = vec![Ok(0..2), Err(false), Ok(2..4)]; /// let it = input.iter().cloned().flatten_ok(); /// itertools::assert_equal(it.clone(), vec![Ok(0), Ok(1), Err(false), Ok(2), Ok(3)]); - /// + /// /// // This can also be used to propagate errors when collecting. /// let output_result: Result, bool> = it.collect(); /// assert_eq!(output_result, Err(false)); @@ -1389,6 +1391,53 @@ pub trait Itertools : Iterator { adaptors::take_while_ref(self, accept) } + /// An iterator adaptor that consumes elements while the given predicate is + /// true, including the element for which the predicate first returned + /// false. + /// + /// The [`.take_while()`][std::iter::Iterator::take_while] adaptor is useful + /// when you want items satisfying a predicate, but to know when to stop + /// taking elements, we have to consume that last element that doesn't + /// satisfy the predicate. This adaptor simply includest that element where + /// [`.take_while()`][std::iter::Iterator::take_while] would drop it. + /// + /// The [`.take_while_ref()`][crate::Itertools::take_while_ref] adaptor + /// serves a similar purpose, but this adaptor doesn't require cloning the + /// underlying elements. + /// + /// # Examples + /// + /// ```rust + /// use itertools::Itertools; + /// + /// let items = vec![1, 2, 3, 4, 5]; + /// let filtered: Vec = items.into_iter().take_until(|&n| n % 3 != 0).collect(); + /// assert_eq!(filtered, vec![1, 2, 3]); + /// ``` + /// + /// ```rust + /// use itertools::Itertools; + /// #[derive(Debug, PartialEq)] + /// struct NoCloneImpl(i32); + /// + /// let non_clonable_items: Vec<_> = vec![1, 2, 3, 4, 5] + /// .into_iter() + /// .map(NoCloneImpl) + /// .collect(); + /// let filtered: Vec<_> = non_clonable_items + /// .into_iter() + /// .take_until(|n| n.0 % 3 != 0) + /// .collect(); + /// let expected: Vec<_> = vec![1, 2, 3].into_iter().map(NoCloneImpl).collect(); + /// assert_eq!(filtered, expected); + fn take_until(&mut self, accept: F) -> TakeUntil + where + Self: Sized, + F: FnMut(&Self::Item) -> bool, + { + take_until::TakeUntil::new(self, accept) + } + /// Return an iterator adaptor that filters `Option` iterator elements /// and produces `A`. Stops on the first `None` encountered. /// @@ -1812,14 +1861,14 @@ pub trait Itertools : Iterator { /// /// #[derive(PartialEq, Debug)] /// enum Enum { A, B, C, D, E, } - /// + /// /// let mut iter = vec![Enum::A, Enum::B, Enum::C, Enum::D].into_iter(); - /// + /// /// // search `iter` for `B` /// assert_eq!(iter.contains(&Enum::B), true); /// // `B` was found, so the iterator now rests at the item after `B` (i.e, `C`). /// assert_eq!(iter.next(), Some(Enum::C)); - /// + /// /// // search `iter` for `E` /// assert_eq!(iter.contains(&Enum::E), false); /// // `E` wasn't found, so `iter` is now exhausted @@ -2870,13 +2919,13 @@ pub trait Itertools : Iterator { group_map::into_group_map_by(self, f) } - /// Constructs a `GroupingMap` to be used later with one of the efficient + /// Constructs a `GroupingMap` to be used later with one of the efficient /// group-and-fold operations it allows to perform. - /// + /// /// The input iterator must yield item in the form of `(K, V)` where the /// value of type `K` will be used as key to identify the groups and the /// value of type `V` as value for the folding operation. - /// + /// /// See [`GroupingMap`] for more informations /// on what operations are available. #[cfg(feature = "use_std")] @@ -2887,12 +2936,12 @@ pub trait Itertools : Iterator { grouping_map::new(self) } - /// Constructs a `GroupingMap` to be used later with one of the efficient + /// Constructs a `GroupingMap` to be used later with one of the efficient /// group-and-fold operations it allows to perform. - /// + /// /// The values from this iterator will be used as values for the folding operation /// while the keys will be obtained from the values by calling `key_mapper`. - /// + /// /// See [`GroupingMap`] for more informations /// on what operations are available. #[cfg(feature = "use_std")] @@ -3603,7 +3652,7 @@ pub trait Itertools : Iterator { /// first_name: &'static str, /// last_name: &'static str, /// } - /// + /// /// let characters = /// vec![ /// Character { first_name: "Amy", last_name: "Pond" }, @@ -3614,12 +3663,12 @@ pub trait Itertools : Iterator { /// Character { first_name: "James", last_name: "Norington" }, /// Character { first_name: "James", last_name: "Kirk" }, /// ]; - /// - /// let first_name_frequency = + /// + /// let first_name_frequency = /// characters /// .into_iter() /// .counts_by(|c| c.first_name); - /// + /// /// assert_eq!(first_name_frequency["Amy"], 3); /// assert_eq!(first_name_frequency["James"], 4); /// assert_eq!(first_name_frequency.contains_key("Asha"), false); @@ -3640,7 +3689,7 @@ pub trait Itertools : Iterator { /// column. /// /// This function is, in some sense, the opposite of [`multizip`]. - /// + /// /// ``` /// use itertools::Itertools; /// diff --git a/src/take_until.rs b/src/take_until.rs new file mode 100644 index 000000000..a33ae44ce --- /dev/null +++ b/src/take_until.rs @@ -0,0 +1,54 @@ +use std::fmt; + +/// An iterator adaptor that consumes elements while the given predicate is true, including the +/// element for which the predicate first returned false. +/// +/// See [`.take_until()`](crate::Itertools::take_until) for more information. +#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] +pub struct TakeUntil<'a, I: 'a, F> { + iter: &'a mut I, + f: F, + done: bool, +} + +impl<'a, I, F> TakeUntil<'a, I, F> +where + I: Iterator, + F: FnMut(&I::Item) -> bool, +{ + /// Create a new [`TakeUntil`] from an iterator and a predicate. + pub fn new(iter: &'a mut I, f: F) -> Self { + Self { iter, f, done: false} + } +} + +impl<'a, I, F> fmt::Debug for TakeUntil<'a, I, F> + where I: Iterator + fmt::Debug, +{ + debug_fmt_fields!(TakeUntil, iter); +} + +impl<'a, I, F> Iterator for TakeUntil<'a, I, F> +where + I: Iterator, + F: FnMut(&I::Item) -> bool +{ + type Item = I::Item; + + fn next(&mut self) -> Option { + if self.done { + None + } else { + self.iter.next().map(|item| { + if !(self.f)(&item) { + self.done = true; + } + item + }) + } + } + + fn size_hint(&self) -> (usize, Option) { + (0, self.iter.size_hint().1) + } +} \ No newline at end of file From 60d5c7cce3c620adf0b9416e825d9a553037f1cc Mon Sep 17 00:00:00 2001 From: Erik Rhodes Date: Mon, 23 May 2022 15:47:16 -0600 Subject: [PATCH 2/7] added test showing difference between take_until and take_while --- src/lib.rs | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 364409ae0..602bdc857 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1411,12 +1411,31 @@ pub trait Itertools : Iterator { /// use itertools::Itertools; /// /// let items = vec![1, 2, 3, 4, 5]; - /// let filtered: Vec = items.into_iter().take_until(|&n| n % 3 != 0).collect(); + /// let filtered: Vec<_> = items.into_iter().take_until(|&n| n % 3 != 0).collect(); + /// /// assert_eq!(filtered, vec![1, 2, 3]); /// ``` /// /// ```rust /// use itertools::Itertools; + /// let items = vec![1, 2, 3, 4, 5]; + /// + /// let take_until_result: Vec<_> = items + /// .clone() + /// .into_iter() + /// .take_until(|&n| n % 3 != 0) + /// .collect(); + /// let take_while_result: Vec<_> = items + /// .into_iter() + /// .take_while(|&n| n % 3 != 0) + /// .collect(); + /// + /// assert_eq!(take_until_result, vec![1, 2, 3]); + /// assert_eq!(take_while_result, vec![1, 2]); + /// ``` + /// + /// ```rust + /// use itertools::Itertools; /// #[derive(Debug, PartialEq)] /// struct NoCloneImpl(i32); /// From 37cd39134ad394612bf5cb9ddf2a3cce36b3a8d9 Mon Sep 17 00:00:00 2001 From: Erik Rhodes Date: Mon, 23 May 2022 15:51:03 -0600 Subject: [PATCH 3/7] changed docs formatting to fit in with existing code --- src/lib.rs | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 602bdc857..ca8bba7d9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1391,24 +1391,22 @@ pub trait Itertools : Iterator { adaptors::take_while_ref(self, accept) } - /// An iterator adaptor that consumes elements while the given predicate is - /// true, including the element for which the predicate first returned - /// false. + /// Returns an iterator adaptor that consumes elements while the given + /// predicate is `true`, *including* the element for which the predicate + /// first returned `false`. /// /// The [`.take_while()`][std::iter::Iterator::take_while] adaptor is useful /// when you want items satisfying a predicate, but to know when to stop /// taking elements, we have to consume that last element that doesn't - /// satisfy the predicate. This adaptor simply includest that element where + /// satisfy the predicate. This adaptor simply includes that element where /// [`.take_while()`][std::iter::Iterator::take_while] would drop it. /// /// The [`.take_while_ref()`][crate::Itertools::take_while_ref] adaptor - /// serves a similar purpose, but this adaptor doesn't require cloning the - /// underlying elements. - /// - /// # Examples + /// serves a similar purpose, but this adaptor doesn't require [`Clone`]ing + /// the underlying elements. /// /// ```rust - /// use itertools::Itertools; + /// # use itertools::Itertools; /// /// let items = vec![1, 2, 3, 4, 5]; /// let filtered: Vec<_> = items.into_iter().take_until(|&n| n % 3 != 0).collect(); @@ -1417,7 +1415,7 @@ pub trait Itertools : Iterator { /// ``` /// /// ```rust - /// use itertools::Itertools; + /// # use itertools::Itertools; /// let items = vec![1, 2, 3, 4, 5]; /// /// let take_until_result: Vec<_> = items @@ -1435,7 +1433,7 @@ pub trait Itertools : Iterator { /// ``` /// /// ```rust - /// use itertools::Itertools; + /// # use itertools::Itertools; /// #[derive(Debug, PartialEq)] /// struct NoCloneImpl(i32); /// From d67e86f16d11827779d49f321884bb363f603352 Mon Sep 17 00:00:00 2001 From: Erik Rhodes Date: Wed, 25 May 2022 12:02:04 -0600 Subject: [PATCH 4/7] added fusediterator impl and improved size hint, inspired by hdevalke/take-until --- src/take_until.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/take_until.rs b/src/take_until.rs index a33ae44ce..ae166d260 100644 --- a/src/take_until.rs +++ b/src/take_until.rs @@ -1,3 +1,4 @@ +use core::iter::FusedIterator; use std::fmt; /// An iterator adaptor that consumes elements while the given predicate is true, including the @@ -49,6 +50,17 @@ where } fn size_hint(&self) -> (usize, Option) { - (0, self.iter.size_hint().1) + if self.done { + (0, Some(0)) + } else { + (0, self.iter.size_hint().1) + } } +} + +impl FusedIterator for TakeUntil<'_, I, F> +where + I: Iterator, + F: FnMut(&I::Item) -> bool +{ } \ No newline at end of file From 681ed7a038a9e8e8abcd4978199ba834038641d2 Mon Sep 17 00:00:00 2001 From: Erik Rhodes Date: Wed, 25 May 2022 12:10:28 -0600 Subject: [PATCH 5/7] reversed semantics of predicate to read more naturally (takes elements until the predicate returns true) --- src/lib.rs | 17 +++++++++++------ src/take_until.rs | 6 +++--- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index ca8bba7d9..d433374bf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1392,15 +1392,20 @@ pub trait Itertools : Iterator { } /// Returns an iterator adaptor that consumes elements while the given - /// predicate is `true`, *including* the element for which the predicate - /// first returned `false`. + /// predicate is `false`, *including* the element for which the predicate + /// first returned `true`. /// /// The [`.take_while()`][std::iter::Iterator::take_while] adaptor is useful /// when you want items satisfying a predicate, but to know when to stop /// taking elements, we have to consume that last element that doesn't - /// satisfy the predicate. This adaptor simply includes that element where + /// satisfy the predicate. This adaptor includes that element where /// [`.take_while()`][std::iter::Iterator::take_while] would drop it. /// + /// Note that the semantics of this predicate are reversed from + /// [`.take_while()`][std::iter::Iterator::take_while], i.e. this function's + /// predicate yields elements when it evaluates to `false` instead of when + /// it evaluates to `true`. + /// /// The [`.take_while_ref()`][crate::Itertools::take_while_ref] adaptor /// serves a similar purpose, but this adaptor doesn't require [`Clone`]ing /// the underlying elements. @@ -1409,7 +1414,7 @@ pub trait Itertools : Iterator { /// # use itertools::Itertools; /// /// let items = vec![1, 2, 3, 4, 5]; - /// let filtered: Vec<_> = items.into_iter().take_until(|&n| n % 3 != 0).collect(); + /// let filtered: Vec<_> = items.into_iter().take_until(|&n| n % 3 == 0).collect(); /// /// assert_eq!(filtered, vec![1, 2, 3]); /// ``` @@ -1421,7 +1426,7 @@ pub trait Itertools : Iterator { /// let take_until_result: Vec<_> = items /// .clone() /// .into_iter() - /// .take_until(|&n| n % 3 != 0) + /// .take_until(|&n| n % 3 == 0) /// .collect(); /// let take_while_result: Vec<_> = items /// .into_iter() @@ -1443,7 +1448,7 @@ pub trait Itertools : Iterator { /// .collect(); /// let filtered: Vec<_> = non_clonable_items /// .into_iter() - /// .take_until(|n| n.0 % 3 != 0) + /// .take_until(|n| n.0 % 3 == 0) /// .collect(); /// let expected: Vec<_> = vec![1, 2, 3].into_iter().map(NoCloneImpl).collect(); /// assert_eq!(filtered, expected); diff --git a/src/take_until.rs b/src/take_until.rs index ae166d260..40a590361 100644 --- a/src/take_until.rs +++ b/src/take_until.rs @@ -1,8 +1,8 @@ use core::iter::FusedIterator; use std::fmt; -/// An iterator adaptor that consumes elements while the given predicate is true, including the -/// element for which the predicate first returned false. +/// An iterator adaptor that consumes elements while the given predicate is false, including the +/// element for which the predicate first returned true. /// /// See [`.take_until()`](crate::Itertools::take_until) for more information. #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] @@ -41,7 +41,7 @@ where None } else { self.iter.next().map(|item| { - if !(self.f)(&item) { + if (self.f)(&item) { self.done = true; } item From 0b49d8b4b2437f83037d458c933ac6f2ec619287 Mon Sep 17 00:00:00 2001 From: Erik Rhodes Date: Wed, 25 May 2022 12:25:28 -0600 Subject: [PATCH 6/7] changed name to take_while_inclusive and reversed semantics back to match take_while --- src/lib.rs | 26 +++++++++---------- ...{take_until.rs => take_while_inclusive.rs} | 22 ++++++++-------- 2 files changed, 23 insertions(+), 25 deletions(-) rename src/{take_until.rs => take_while_inclusive.rs} (61%) diff --git a/src/lib.rs b/src/lib.rs index d433374bf..5e36df0ba 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -146,7 +146,7 @@ pub mod structs { pub use crate::repeatn::RepeatN; #[allow(deprecated)] pub use crate::sources::{RepeatCall, Unfold, Iterate}; - pub use crate::take_until::TakeUntil; + pub use crate::take_while_inclusive::TakeWhileInclusive; #[cfg(feature = "use_alloc")] pub use crate::tee::Tee; pub use crate::tuple_impl::{TupleBuffer, TupleWindows, CircularTupleWindows, Tuples}; @@ -234,7 +234,7 @@ mod rciter_impl; mod repeatn; mod size_hint; mod sources; -mod take_until; +mod take_while_inclusive; #[cfg(feature = "use_alloc")] mod tee; mod tuple_impl; @@ -1392,8 +1392,8 @@ pub trait Itertools : Iterator { } /// Returns an iterator adaptor that consumes elements while the given - /// predicate is `false`, *including* the element for which the predicate - /// first returned `true`. + /// predicate is `true`, *including* the element for which the predicate + /// first returned `false`. /// /// The [`.take_while()`][std::iter::Iterator::take_while] adaptor is useful /// when you want items satisfying a predicate, but to know when to stop @@ -1401,11 +1401,6 @@ pub trait Itertools : Iterator { /// satisfy the predicate. This adaptor includes that element where /// [`.take_while()`][std::iter::Iterator::take_while] would drop it. /// - /// Note that the semantics of this predicate are reversed from - /// [`.take_while()`][std::iter::Iterator::take_while], i.e. this function's - /// predicate yields elements when it evaluates to `false` instead of when - /// it evaluates to `true`. - /// /// The [`.take_while_ref()`][crate::Itertools::take_while_ref] adaptor /// serves a similar purpose, but this adaptor doesn't require [`Clone`]ing /// the underlying elements. @@ -1414,7 +1409,10 @@ pub trait Itertools : Iterator { /// # use itertools::Itertools; /// /// let items = vec![1, 2, 3, 4, 5]; - /// let filtered: Vec<_> = items.into_iter().take_until(|&n| n % 3 == 0).collect(); + /// let filtered: Vec<_> = items + /// .into_iter() + /// .take_while_inclusive(|&n| n % 3 != 0) + /// .collect(); /// /// assert_eq!(filtered, vec![1, 2, 3]); /// ``` @@ -1426,7 +1424,7 @@ pub trait Itertools : Iterator { /// let take_until_result: Vec<_> = items /// .clone() /// .into_iter() - /// .take_until(|&n| n % 3 == 0) + /// .take_while_inclusive(|&n| n % 3 != 0) /// .collect(); /// let take_while_result: Vec<_> = items /// .into_iter() @@ -1448,16 +1446,16 @@ pub trait Itertools : Iterator { /// .collect(); /// let filtered: Vec<_> = non_clonable_items /// .into_iter() - /// .take_until(|n| n.0 % 3 == 0) + /// .take_while_inclusive(|n| n.0 % 3 != 0) /// .collect(); /// let expected: Vec<_> = vec![1, 2, 3].into_iter().map(NoCloneImpl).collect(); /// assert_eq!(filtered, expected); - fn take_until(&mut self, accept: F) -> TakeUntil + fn take_while_inclusive(&mut self, accept: F) -> TakeWhileInclusive where Self: Sized, F: FnMut(&Self::Item) -> bool, { - take_until::TakeUntil::new(self, accept) + take_while_inclusive::TakeWhileInclusive::new(self, accept) } /// Return an iterator adaptor that filters `Option` iterator elements diff --git a/src/take_until.rs b/src/take_while_inclusive.rs similarity index 61% rename from src/take_until.rs rename to src/take_while_inclusive.rs index 40a590361..ed577ef56 100644 --- a/src/take_until.rs +++ b/src/take_while_inclusive.rs @@ -1,35 +1,35 @@ use core::iter::FusedIterator; use std::fmt; -/// An iterator adaptor that consumes elements while the given predicate is false, including the -/// element for which the predicate first returned true. +/// An iterator adaptor that consumes elements while the given predicate is `true`, including the +/// element for which the predicate first returned `false`. /// -/// See [`.take_until()`](crate::Itertools::take_until) for more information. +/// See [`.take_while_inclusive()`](crate::Itertools::take_while_inclusive) for more information. #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct TakeUntil<'a, I: 'a, F> { +pub struct TakeWhileInclusive<'a, I: 'a, F> { iter: &'a mut I, f: F, done: bool, } -impl<'a, I, F> TakeUntil<'a, I, F> +impl<'a, I, F> TakeWhileInclusive<'a, I, F> where I: Iterator, F: FnMut(&I::Item) -> bool, { - /// Create a new [`TakeUntil`] from an iterator and a predicate. + /// Create a new [`TakeWhileInclusive`] from an iterator and a predicate. pub fn new(iter: &'a mut I, f: F) -> Self { Self { iter, f, done: false} } } -impl<'a, I, F> fmt::Debug for TakeUntil<'a, I, F> +impl<'a, I, F> fmt::Debug for TakeWhileInclusive<'a, I, F> where I: Iterator + fmt::Debug, { - debug_fmt_fields!(TakeUntil, iter); + debug_fmt_fields!(TakeWhileInclusive, iter); } -impl<'a, I, F> Iterator for TakeUntil<'a, I, F> +impl<'a, I, F> Iterator for TakeWhileInclusive<'a, I, F> where I: Iterator, F: FnMut(&I::Item) -> bool @@ -41,7 +41,7 @@ where None } else { self.iter.next().map(|item| { - if (self.f)(&item) { + if !(self.f)(&item) { self.done = true; } item @@ -58,7 +58,7 @@ where } } -impl FusedIterator for TakeUntil<'_, I, F> +impl FusedIterator for TakeWhileInclusive<'_, I, F> where I: Iterator, F: FnMut(&I::Item) -> bool From 91fe99ef8c0555702a4617407a94b919937ce4eb Mon Sep 17 00:00:00 2001 From: Erik Rhodes Date: Wed, 25 May 2022 12:42:10 -0600 Subject: [PATCH 7/7] renamed some items and improved docs for clarity --- src/lib.rs | 14 +++++++------- src/take_while_inclusive.rs | 16 +++++++++------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 5e36df0ba..057920aed 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1397,7 +1397,7 @@ pub trait Itertools : Iterator { /// /// The [`.take_while()`][std::iter::Iterator::take_while] adaptor is useful /// when you want items satisfying a predicate, but to know when to stop - /// taking elements, we have to consume that last element that doesn't + /// taking elements, we have to consume that first element that doesn't /// satisfy the predicate. This adaptor includes that element where /// [`.take_while()`][std::iter::Iterator::take_while] would drop it. /// @@ -1407,7 +1407,6 @@ pub trait Itertools : Iterator { /// /// ```rust /// # use itertools::Itertools; - /// /// let items = vec![1, 2, 3, 4, 5]; /// let filtered: Vec<_> = items /// .into_iter() @@ -1421,9 +1420,9 @@ pub trait Itertools : Iterator { /// # use itertools::Itertools; /// let items = vec![1, 2, 3, 4, 5]; /// - /// let take_until_result: Vec<_> = items - /// .clone() - /// .into_iter() + /// let take_while_inclusive_result: Vec<_> = items + /// .iter() + /// .copied() /// .take_while_inclusive(|&n| n % 3 != 0) /// .collect(); /// let take_while_result: Vec<_> = items @@ -1431,8 +1430,10 @@ pub trait Itertools : Iterator { /// .take_while(|&n| n % 3 != 0) /// .collect(); /// - /// assert_eq!(take_until_result, vec![1, 2, 3]); + /// assert_eq!(take_while_inclusive_result, vec![1, 2, 3]); /// assert_eq!(take_while_result, vec![1, 2]); + /// // both iterators have the same items remaining at this point---the 3 + /// // is lost from the `take_while` vec /// ``` /// /// ```rust @@ -2763,7 +2764,6 @@ pub trait Itertools : Iterator { /// itertools::assert_equal(oldest_people_first, /// vec!["Jill", "Jack", "Jane", "John"]); /// ``` - /// ``` #[cfg(feature = "use_alloc")] fn sorted_by_cached_key(self, f: F) -> VecIntoIter where diff --git a/src/take_while_inclusive.rs b/src/take_while_inclusive.rs index ed577ef56..e2a7479e0 100644 --- a/src/take_while_inclusive.rs +++ b/src/take_while_inclusive.rs @@ -1,14 +1,16 @@ use core::iter::FusedIterator; use std::fmt; -/// An iterator adaptor that consumes elements while the given predicate is `true`, including the -/// element for which the predicate first returned `false`. +/// An iterator adaptor that consumes elements while the given predicate is +/// `true`, including the element for which the predicate first returned +/// `false`. /// -/// See [`.take_while_inclusive()`](crate::Itertools::take_while_inclusive) for more information. +/// See [`.take_while_inclusive()`](crate::Itertools::take_while_inclusive) +/// for more information. #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] pub struct TakeWhileInclusive<'a, I: 'a, F> { iter: &'a mut I, - f: F, + predicate: F, done: bool, } @@ -18,8 +20,8 @@ where F: FnMut(&I::Item) -> bool, { /// Create a new [`TakeWhileInclusive`] from an iterator and a predicate. - pub fn new(iter: &'a mut I, f: F) -> Self { - Self { iter, f, done: false} + pub fn new(iter: &'a mut I, predicate: F) -> Self { + Self { iter, predicate, done: false} } } @@ -41,7 +43,7 @@ where None } else { self.iter.next().map(|item| { - if !(self.f)(&item) { + if !(self.predicate)(&item) { self.done = true; } item