about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/libcore/iter/iterator.rs31
-rw-r--r--src/libcore/iter/mod.rs100
-rw-r--r--src/libcore/option.rs42
-rw-r--r--src/libcore/tests/iter.rs17
-rw-r--r--src/libcore/tests/lib.rs2
-rw-r--r--src/libcore/tests/option.rs21
6 files changed, 212 insertions, 1 deletions
diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs
index 230d7695166..1ea500858ed 100644
--- a/src/libcore/iter/iterator.rs
+++ b/src/libcore/iter/iterator.rs
@@ -2,7 +2,7 @@ use cmp::Ordering;
 use ops::Try;
 
 use super::LoopState;
-use super::{Chain, Cycle, Cloned, Enumerate, Filter, FilterMap, Fuse};
+use super::{Chain, Cycle, Copied, Cloned, Enumerate, Filter, FilterMap, Fuse};
 use super::{Flatten, FlatMap, flatten_compat};
 use super::{Inspect, Map, Peekable, Scan, Skip, SkipWhile, StepBy, Take, TakeWhile, Rev};
 use super::{Zip, Sum, Product};
@@ -2225,6 +2225,35 @@ pub trait Iterator {
         (ts, us)
     }
 
+    /// Creates an iterator which copies all of its elements.
+    ///
+    /// This is useful when you have an iterator over `&T`, but you need an
+    /// iterator over `T`.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// #![feature(iter_copied)]
+    ///
+    /// let a = [1, 2, 3];
+    ///
+    /// let v_cloned: Vec<_> = a.iter().copied().collect();
+    ///
+    /// // copied is the same as .map(|&x| x)
+    /// let v_map: Vec<_> = a.iter().map(|&x| x).collect();
+    ///
+    /// assert_eq!(v_cloned, vec![1, 2, 3]);
+    /// assert_eq!(v_map, vec![1, 2, 3]);
+    /// ```
+    #[unstable(feature = "iter_copied", issue = "57127")]
+    fn copied<'a, T: 'a>(self) -> Copied<Self>
+        where Self: Sized + Iterator<Item=&'a T>, T: Copy
+    {
+        Copied { it: self }
+    }
+
     /// Creates an iterator which [`clone`]s all of its elements.
     ///
     /// This is useful when you have an iterator over `&T`, but you need an
diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs
index 734f2a0b2cc..03369d6c8f3 100644
--- a/src/libcore/iter/mod.rs
+++ b/src/libcore/iter/mod.rs
@@ -497,6 +497,106 @@ impl<I> FusedIterator for Rev<I>
 unsafe impl<I> TrustedLen for Rev<I>
     where I: TrustedLen + DoubleEndedIterator {}
 
+/// An iterator that copies the elements of an underlying iterator.
+///
+/// This `struct` is created by the [`copied`] method on [`Iterator`]. See its
+/// documentation for more.
+///
+/// [`copied`]: trait.Iterator.html#method.copied
+/// [`Iterator`]: trait.Iterator.html
+#[unstable(feature = "iter_copied", issue = "57127")]
+#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
+#[derive(Clone, Debug)]
+pub struct Copied<I> {
+    it: I,
+}
+
+#[unstable(feature = "iter_copied", issue = "57127")]
+impl<'a, I, T: 'a> Iterator for Copied<I>
+    where I: Iterator<Item=&'a T>, T: Copy
+{
+    type Item = T;
+
+    fn next(&mut self) -> Option<T> {
+        self.it.next().copied()
+    }
+
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        self.it.size_hint()
+    }
+
+    fn try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R where
+        Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try<Ok=B>
+    {
+        self.it.try_fold(init, move |acc, &elt| f(acc, elt))
+    }
+
+    fn fold<Acc, F>(self, init: Acc, mut f: F) -> Acc
+        where F: FnMut(Acc, Self::Item) -> Acc,
+    {
+        self.it.fold(init, move |acc, &elt| f(acc, elt))
+    }
+}
+
+#[unstable(feature = "iter_copied", issue = "57127")]
+impl<'a, I, T: 'a> DoubleEndedIterator for Copied<I>
+    where I: DoubleEndedIterator<Item=&'a T>, T: Copy
+{
+    fn next_back(&mut self) -> Option<T> {
+        self.it.next_back().copied()
+    }
+
+    fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R where
+        Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try<Ok=B>
+    {
+        self.it.try_rfold(init, move |acc, &elt| f(acc, elt))
+    }
+
+    fn rfold<Acc, F>(self, init: Acc, mut f: F) -> Acc
+        where F: FnMut(Acc, Self::Item) -> Acc,
+    {
+        self.it.rfold(init, move |acc, &elt| f(acc, elt))
+    }
+}
+
+#[unstable(feature = "iter_copied", issue = "57127")]
+impl<'a, I, T: 'a> ExactSizeIterator for Copied<I>
+    where I: ExactSizeIterator<Item=&'a T>, T: Copy
+{
+    fn len(&self) -> usize {
+        self.it.len()
+    }
+
+    fn is_empty(&self) -> bool {
+        self.it.is_empty()
+    }
+}
+
+#[unstable(feature = "iter_copied", issue = "57127")]
+impl<'a, I, T: 'a> FusedIterator for Copied<I>
+    where I: FusedIterator<Item=&'a T>, T: Copy
+{}
+
+#[doc(hidden)]
+unsafe impl<'a, I, T: 'a> TrustedRandomAccess for Copied<I>
+    where I: TrustedRandomAccess<Item=&'a T>, T: Copy
+{
+    unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item {
+        *self.it.get_unchecked(i)
+    }
+
+    #[inline]
+    fn may_have_side_effect() -> bool {
+        I::may_have_side_effect()
+    }
+}
+
+#[unstable(feature = "iter_copied", issue = "57127")]
+unsafe impl<'a, I, T: 'a> TrustedLen for Copied<I>
+    where I: TrustedLen<Item=&'a T>,
+          T: Copy
+{}
+
 /// An iterator that clones the elements of an underlying iterator.
 ///
 /// This `struct` is created by the [`cloned`] method on [`Iterator`]. See its
diff --git a/src/libcore/option.rs b/src/libcore/option.rs
index b6af90337dd..6d4f4be1a17 100644
--- a/src/libcore/option.rs
+++ b/src/libcore/option.rs
@@ -874,6 +874,48 @@ impl<T> Option<T> {
     }
 }
 
+impl<'a, T: Copy> Option<&'a T> {
+    /// Maps an `Option<&T>` to an `Option<T>` by copying the contents of the
+    /// option.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(copied)]
+    ///
+    /// let x = 12;
+    /// let opt_x = Some(&x);
+    /// assert_eq!(opt_x, Some(&12));
+    /// let copied = opt_x.copied();
+    /// assert_eq!(copied, Some(12));
+    /// ```
+    #[unstable(feature = "copied", issue = "57126")]
+    pub fn copied(self) -> Option<T> {
+        self.map(|&t| t)
+    }
+}
+
+impl<'a, T: Copy> Option<&'a mut T> {
+    /// Maps an `Option<&mut T>` to an `Option<T>` by copying the contents of the
+    /// option.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(copied)]
+    ///
+    /// let mut x = 12;
+    /// let opt_x = Some(&mut x);
+    /// assert_eq!(opt_x, Some(&mut 12));
+    /// let copied = opt_x.copied();
+    /// assert_eq!(copied, Some(12));
+    /// ```
+    #[unstable(feature = "copied", issue = "57126")]
+    pub fn copied(self) -> Option<T> {
+        self.map(|&mut t| t)
+    }
+}
+
 impl<'a, T: Clone> Option<&'a T> {
     /// Maps an `Option<&T>` to an `Option<T>` by cloning the contents of the
     /// option.
diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs
index 2029f3fa131..cf19851c17b 100644
--- a/src/libcore/tests/iter.rs
+++ b/src/libcore/tests/iter.rs
@@ -1254,6 +1254,23 @@ fn test_rev() {
 }
 
 #[test]
+fn test_copied() {
+    let xs = [2, 4, 6, 8];
+
+    let mut it = xs.iter().copied();
+    assert_eq!(it.len(), 4);
+    assert_eq!(it.next(), Some(2));
+    assert_eq!(it.len(), 3);
+    assert_eq!(it.next(), Some(4));
+    assert_eq!(it.len(), 2);
+    assert_eq!(it.next_back(), Some(8));
+    assert_eq!(it.len(), 1);
+    assert_eq!(it.next_back(), Some(6));
+    assert_eq!(it.len(), 0);
+    assert_eq!(it.next_back(), None);
+}
+
+#[test]
 fn test_cloned() {
     let xs = [2, 4, 6, 8];
 
diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs
index 520fd74c7f7..72846daf16a 100644
--- a/src/libcore/tests/lib.rs
+++ b/src/libcore/tests/lib.rs
@@ -1,5 +1,6 @@
 #![feature(box_syntax)]
 #![feature(cell_update)]
+#![feature(copied)]
 #![feature(core_private_bignum)]
 #![feature(core_private_diy_float)]
 #![feature(dec2flt)]
@@ -9,6 +10,7 @@
 #![feature(flt2dec)]
 #![feature(fmt_internals)]
 #![feature(hashmap_internals)]
+#![feature(iter_copied)]
 #![feature(iter_nth_back)]
 #![feature(iter_unfold)]
 #![feature(pattern)]
diff --git a/src/libcore/tests/option.rs b/src/libcore/tests/option.rs
index 896479c352a..b059b134868 100644
--- a/src/libcore/tests/option.rs
+++ b/src/libcore/tests/option.rs
@@ -238,6 +238,27 @@ fn test_collect() {
     assert!(v == None);
 }
 
+#[test]
+fn test_copied() {
+    let val = 1;
+    let val_ref = &val;
+    let opt_none: Option<&'static u32> = None;
+    let opt_ref = Some(&val);
+    let opt_ref_ref = Some(&val_ref);
+
+    // None works
+    assert_eq!(opt_none.clone(), None);
+    assert_eq!(opt_none.copied(), None);
+
+    // Immutable ref works
+    assert_eq!(opt_ref.clone(), Some(&val));
+    assert_eq!(opt_ref.copied(), Some(1));
+
+    // Double Immutable ref works
+    assert_eq!(opt_ref_ref.clone(), Some(&val_ref));
+    assert_eq!(opt_ref_ref.clone().copied(), Some(&val));
+    assert_eq!(opt_ref_ref.copied().copied(), Some(1));
+}
 
 #[test]
 fn test_cloned() {