diff --git a/library/core/src/iter/traits/collect.rs b/library/core/src/iter/traits/collect.rs
index 56fad602cf9c8..4df8c5212e898 100644
--- a/library/core/src/iter/traits/collect.rs
+++ b/library/core/src/iter/traits/collect.rs
@@ -1,3 +1,5 @@
+use crate::marker::PhantomData;
+
/// Conversion from an [`Iterator`].
///
/// By implementing `FromIterator` for a type, you define how it will be
@@ -346,10 +348,37 @@ pub trait Extend {
/// Reserves capacity in a collection for the given number of additional elements.
///
- /// The default implementation does nothing.
+ /// The default implementation forwards to `extend` with an iterator having
+ /// the given requested capacity as `size_hint`, which has the effect of
+ /// reserving if `extend` takes into account its argument's size hint in
+ /// order to reserve capacity.
#[unstable(feature = "extend_one", issue = "72631")]
fn extend_reserve(&mut self, additional: usize) {
- let _ = additional;
+ struct ReserveHint {
+ additional: usize,
+ item: PhantomData,
+ }
+
+ // DO NOT implement TrustedLen, because the real len is actually 0.
+ impl Iterator for ReserveHint {
+ type Item = A;
+
+ fn next(&mut self) -> Option {
+ None
+ }
+
+ fn size_hint(&self) -> (usize, Option) {
+ (self.additional, Some(self.additional))
+ }
+ }
+
+ impl ExactSizeIterator for ReserveHint {
+ fn len(&self) -> usize {
+ self.additional
+ }
+ }
+
+ self.extend(ReserveHint { additional, item: PhantomData })
}
}
diff --git a/library/core/tests/iter/traits/collect.rs b/library/core/tests/iter/traits/collect.rs
new file mode 100644
index 0000000000000..d50f6d81d438c
--- /dev/null
+++ b/library/core/tests/iter/traits/collect.rs
@@ -0,0 +1,27 @@
+#[test]
+fn test_extend_reserve() {
+ struct Collection {
+ len: usize,
+ capacity: usize,
+ }
+
+ impl Extend for Collection {
+ fn extend>(&mut self, elements: I) {
+ let iter = elements.into_iter();
+ let (lower_bound, _) = iter.size_hint();
+ let expected_len = self.len.saturating_add(lower_bound);
+ if self.capacity < expected_len {
+ // do the reserve
+ self.capacity = expected_len;
+ }
+ // do the extend
+ iter.into_iter().for_each(drop);
+ }
+
+ // no custom implementation of extend_reserve
+ }
+
+ let mut collection = Collection { len: 0, capacity: 0 };
+ collection.extend_reserve(5);
+ assert_eq!(collection.capacity, 5);
+}
diff --git a/library/core/tests/iter/traits/mod.rs b/library/core/tests/iter/traits/mod.rs
index 80619f53f25f9..b00e49b06967f 100644
--- a/library/core/tests/iter/traits/mod.rs
+++ b/library/core/tests/iter/traits/mod.rs
@@ -1,4 +1,5 @@
mod accum;
+mod collect;
mod double_ended;
mod iterator;
mod step;
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index 19bcc45108dfd..f2730fdddcf85 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -23,6 +23,7 @@
#![feature(duration_consts_2)]
#![feature(duration_constants)]
#![feature(exact_size_is_empty)]
+#![feature(extend_one)]
#![feature(extern_types)]
#![feature(flt2dec)]
#![feature(fmt_internals)]