From b61e4c29f1ba369e50254fb8d89197a6b15213e8 Mon Sep 17 00:00:00 2001 From: fren_gor Date: Sun, 16 Jan 2022 19:47:41 +0100 Subject: [PATCH 1/3] Add collect_into and collect_with --- library/core/src/iter/traits/iterator.rs | 148 +++++++++++++++++++++++ 1 file changed, 148 insertions(+) diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 1d947297463d9..01d1b379fce5d 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -1741,6 +1741,154 @@ pub trait Iterator { FromIterator::from_iter(self) } + /// Collects all the items from an iterator into a collection. + /// + /// This method consumes the iterator and adds all its items to the + /// passed collection. The collection is then returned, so the call chain + /// can be continued. + /// + /// The collection is passed and returned by mutable reference. + /// To pass it by by value, use [`collect_with`]. + /// + /// [`collect_with`]: Iterator::collect_with + /// + /// This is useful when you already have a collection and wants to add + /// the iterator items to it. + /// + /// This method is a convenience method to call [Extend::extend](trait.Extend.html), + /// but instead of being called on a collection, it's called on an iterator. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(iter_more_collects)] + /// + /// let a = [1, 2, 3]; + /// let mut vec: Vec:: = Vec::new(); + /// + /// a.iter().map(|&x| x * 2).collect_into(&mut vec); + /// a.iter().map(|&x| x * 10).collect_into(&mut vec); + /// + /// assert_eq!(vec![2, 4, 6, 10, 20, 30], vec); + /// ``` + /// + /// `Vec` can have a manual set capacity to avoid reallocating it: + /// + /// ``` + /// #![feature(iter_more_collects)] + /// + /// let a = [1, 2, 3]; + /// let mut vec: Vec:: = Vec::with_capacity(6); + /// + /// a.iter().map(|&x| x * 2).collect_into(&mut vec); + /// a.iter().map(|&x| x * 10).collect_into(&mut vec); + /// + /// assert_eq!(6, vec.capacity()); + /// ``` + /// + /// The returned mutable reference can be used to continue the call chain: + /// + /// ``` + /// #![feature(iter_more_collects)] + /// + /// let a = [1, 2, 3]; + /// let mut vec: Vec:: = Vec::new(); + /// + /// let count = a.iter().collect_into(&mut vec).iter().count(); + /// + /// assert_eq!(count, vec.len()); + /// println!("Vec len is {}", count); + /// + /// let count = a.iter().collect_into(&mut vec).iter().count(); + /// + /// assert_eq!(count, vec.len()); + /// println!("Vec len now is {}", count); + /// ``` + // must_use not added here since collect_into takes a (mutable) reference + #[inline] + #[unstable(feature = "iter_more_collects", reason = "new API", issue = "none")] + fn collect_into>(self, collection: &mut E) -> &mut E + where + Self: Sized, + { + collection.extend(self); + collection + } + + /// Collects all the items from an iterator with a collection. + /// + /// This method consumes the iterator and adds all its items to the + /// passed collection. The collection is then returned, so the call chain + /// can be continued. + /// + /// The collection is passed and returned by value. To pass it by by mutable + /// reference, use [`collect_into`]. + /// + /// [`collect_into`]: Iterator::collect_into + /// + /// This is useful when you want to pre-allocate memory for the collection + /// that will contains the iterator items. + /// + /// This method is a convenience method to call [Extend::extend](trait.Extend.html), + /// but instead of being called on a collection, it's called on an iterator. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(iter_more_collects)] + /// + /// let a = [1, 2, 3]; + /// + /// let doubled = a.iter() + /// .map(|&x| x * 2) + /// .collect_with(Vec::new()); + /// + /// assert_eq!(vec![2, 4, 6], doubled); + /// ``` + /// + /// Collecting an iterator into a `Vec` with manually set capacity in order + /// to avoid reallocating it: + /// + /// ``` + /// #![feature(iter_more_collects)] + /// + /// let doubled = (0..50).map(|x| x * 2) + /// .collect_with(Vec::with_capacity(50)); + /// + /// assert_eq!(50, doubled.capacity()); + /// ``` + /// + /// Passing to `collect_into` a collection with less capacity than necessary + /// can lead to less performant code: + /// + /// ``` + /// #![feature(iter_more_collects)] + /// + /// let chars = ['g', 'd', 'k', 'k', 'n']; + /// + /// let hello = chars.iter() + /// .map(|&x| x as u8) + /// .map(|x| (x + 1) as char) + /// .collect_with(String::with_capacity(2)); + /// + /// assert_eq!("hello", hello); + /// assert!(5 <= hello.capacity()); // At least one reallocation happened + /// ``` + #[inline] + #[unstable(feature = "iter_more_collects", reason = "new API", issue = "none")] + #[must_use = "if you really need to exhaust the iterator, consider `.for_each(drop)` instead"] + fn collect_with>(self, mut collection: E) -> E + where + Self: Sized, + { + collection.extend(self); + collection + } + /// Consumes an iterator, creating two collections from it. /// /// The predicate passed to `partition()` can return `true`, or `false`. From ada701ceb9f9e9ddc8b160270f73337766fbcf6f Mon Sep 17 00:00:00 2001 From: fren_gor Date: Sun, 16 Jan 2022 19:48:11 +0100 Subject: [PATCH 2/3] Add tests for collect_into and collect_with --- library/core/tests/iter/traits/iterator.rs | 15 +++++++++++++++ library/core/tests/lib.rs | 1 + 2 files changed, 16 insertions(+) diff --git a/library/core/tests/iter/traits/iterator.rs b/library/core/tests/iter/traits/iterator.rs index bb4da83141277..32361a90615c2 100644 --- a/library/core/tests/iter/traits/iterator.rs +++ b/library/core/tests/iter/traits/iterator.rs @@ -496,3 +496,18 @@ fn test_collect() { let b: Vec = a.iter().cloned().collect(); assert!(a == b); } + +#[test] +fn test_collect_into() { + let a = vec![1, 2, 3, 4, 5]; + let mut b = Vec::new(); + a.iter().cloned().collect_into(&mut b); + assert!(a == b); +} + +#[test] +fn test_collect_with() { + let a = vec![1, 2, 3, 4, 5]; + let b = a.iter().cloned().collect_with(Vec::with_capacity(5)); + assert!(a == b); +} diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 841c114063dc1..45a583e2efb7c 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -60,6 +60,7 @@ #![feature(slice_partition_dedup)] #![feature(int_log)] #![feature(iter_advance_by)] +#![feature(iter_more_collects)] #![feature(iter_partition_in_place)] #![feature(iter_intersperse)] #![feature(iter_is_partitioned)] From d6297f53f64ecb20303f343dca595e3a96fe02db Mon Sep 17 00:00:00 2001 From: fren_gor Date: Sun, 16 Jan 2022 23:53:25 +0100 Subject: [PATCH 3/3] Use `vec![0, 1]` instead of `Vec::new()` Co-authored-by: the8472 --- library/core/src/iter/traits/iterator.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 01d1b379fce5d..ba019ccf2e232 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -1766,12 +1766,12 @@ pub trait Iterator { /// #![feature(iter_more_collects)] /// /// let a = [1, 2, 3]; - /// let mut vec: Vec:: = Vec::new(); + /// let mut vec: Vec:: = vec![0, 1]; /// /// a.iter().map(|&x| x * 2).collect_into(&mut vec); /// a.iter().map(|&x| x * 10).collect_into(&mut vec); /// - /// assert_eq!(vec![2, 4, 6, 10, 20, 30], vec); + /// assert_eq!(vec![0, 1, 2, 4, 6, 10, 20, 30], vec); /// ``` /// /// `Vec` can have a manual set capacity to avoid reallocating it: