diff --git a/src/libcore/iter/adapters/chain.rs b/src/libcore/iter/adapters/chain.rs
index 3b669cad1c40f..1c0532632b00b 100644
--- a/src/libcore/iter/adapters/chain.rs
+++ b/src/libcore/iter/adapters/chain.rs
@@ -283,6 +283,36 @@ impl FusedIterator for Chain
B: FusedIterator- ,
{}
+#[stable(feature = "chain_exact_size", since = "1.41.0")]
+impl ExactSizeIterator for Chain
+where
+ A: ExactSizeIterator,
+ B: ExactSizeIterator
- ,
+{
+ /// Returns the exact number of times the iterator will iterate.
+ ///
+ /// # Overflow Behavior
+ ///
+ /// Calling this method on an iterator with more than [`usize::MAX`]
+ /// elements will result in a panic.
+ ///
+ /// # Panics
+ ///
+ /// This panics if the iterator has more than [`usize::MAX`] elements.
+ ///
+ /// [`usize::MAX`]: ../../std/usize/constant.MAX.html
+ fn len(&self) -> usize {
+ match self.state {
+ ChainState::Both => {
+ self.a.len().checked_add(self.b.len())
+ .expect("called `len` on iterator with more than `usize::MAX` elements")
+ }
+ ChainState::Front => self.a.len(),
+ ChainState::Back => self.b.len(),
+ }
+ }
+}
+
#[unstable(feature = "trusted_len", issue = "37572")]
unsafe impl TrustedLen for Chain
where A: TrustedLen, B: TrustedLen
- ,
diff --git a/src/libcore/iter/traits/iterator.rs b/src/libcore/iter/traits/iterator.rs
index b7a35568e3fc5..17f6ea1177ed0 100644
--- a/src/libcore/iter/traits/iterator.rs
+++ b/src/libcore/iter/traits/iterator.rs
@@ -1,3 +1,7 @@
+// ignore-tidy-filelength
+// This file almost exclusively consists of the definition of `Iterator`. We
+// can't split that into multiple files.
+
use crate::cmp::{self, Ordering};
use crate::ops::{Add, Try};
@@ -388,6 +392,26 @@ pub trait Iterator {
/// [`once`] is commonly used to adapt a single value into a chain of
/// other kinds of iteration.
///
+ ///
+ /// # Overflowing behavior for long iterators
+ ///
+ /// This method allows to easily build an iterator that yields more than
+ /// [`usize::MAX`] items. In that case, some methods that return `usize`
+ /// are not guarded against overflow. For example, this includes the
+ /// following methods:
+ ///
+ /// - [`Iterator::count`]
+ /// - [`Iterator::enumerate`]
+ /// - [`Iterator::position`] and [`Iterator::rposition`]
+ /// - [`ExactSizeIterator::len`]
+ ///
+ /// An overflow in those methods leads to a wrong result or a panic. If
+ /// debug assertions are enabled, a panic is guaranteed.
+ ///
+ ///
+ /// [`usize::MAX`]: ../../std/usize/constant.MAX.html
+ ///
+ ///
/// # Examples
///
/// Basic usage:
diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs
index c9096b713f20e..7c3ce7b838906 100644
--- a/src/libcore/tests/iter.rs
+++ b/src/libcore/tests/iter.rs
@@ -256,6 +256,50 @@ fn test_iterator_chain_size_hint() {
assert_eq!(iter.size_hint(), (0, Some(0)));
}
+#[test]
+fn test_iterator_chain_len() {
+ let xs = [0, 1, 2];
+ let ys = [30, 40, 50, 60];
+
+ // First iterator is exhausted first
+ let mut iter = xs.iter().chain(&ys);
+ assert_eq!(iter.len(), 7);
+ assert_eq!(iter.next(), Some(&0));
+ assert_eq!(iter.len(), 6);
+ assert_eq!(iter.next(), Some(&1));
+ assert_eq!(iter.len(), 5);
+ assert_eq!(iter.next_back(), Some(&60));
+ assert_eq!(iter.len(), 4);
+ assert_eq!(iter.next(), Some(&2));
+ assert_eq!(iter.len(), 3);
+ assert_eq!(iter.next(), Some(&30));
+ assert_eq!(iter.len(), 2);
+ assert_eq!(iter.next(), Some(&40));
+ assert_eq!(iter.len(), 1);
+ assert_eq!(iter.next(), Some(&50));
+ assert_eq!(iter.len(), 0);
+ assert_eq!(iter.next(), None);
+
+ // Second iterator is exhausted first
+ let mut iter = xs.iter().chain(&ys);
+ assert_eq!(iter.len(), 7);
+ assert_eq!(iter.next_back(), Some(&60));
+ assert_eq!(iter.len(), 6);
+ assert_eq!(iter.next(), Some(&0));
+ assert_eq!(iter.len(), 5);
+ assert_eq!(iter.next_back(), Some(&50));
+ assert_eq!(iter.len(), 4);
+ assert_eq!(iter.next_back(), Some(&40));
+ assert_eq!(iter.len(), 3);
+ assert_eq!(iter.next_back(), Some(&30));
+ assert_eq!(iter.len(), 2);
+ assert_eq!(iter.next(), Some(&1));
+ assert_eq!(iter.len(), 1);
+ assert_eq!(iter.next(), Some(&2));
+ assert_eq!(iter.len(), 0);
+ assert_eq!(iter.next(), None);
+}
+
#[test]
fn test_zip_nth() {
let xs = [0, 1, 2, 4, 5];