about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2014-11-18 17:21:43 +0000
committerbors <bors@rust-lang.org>2014-11-18 17:21:43 +0000
commit09e2ad13d0aa01143bcb20dece3ff6c5a7e34ea3 (patch)
tree2e0ccae2ab9d6cb5871429279a673c0e4a3f2069 /src
parent618bd5d1c550cbdaac369b01716cc009b9e4d1e7 (diff)
parent4a656062eeca015739015a327192dc067bfb1428 (diff)
downloadrust-09e2ad13d0aa01143bcb20dece3ff6c5a7e34ea3.tar.gz
rust-09e2ad13d0aa01143bcb20dece3ff6c5a7e34ea3.zip
auto merge of #19060 : Gankro/rust/super-cloned, r=aturon
Edit: whoops, didn't mean to hit post.

Anyway, this is something I tried to do when I first implemented cloned, but couldn't figure out. Somewhere between then and the PR actually landing, we got Deref of references, so now this works! :tada: 

Also turns out the test for the functionality was never marked as a #[test]. Oops!

Also added a Cloned iterator adaptor. If this isn't desirable, it can be taken out of the PR (seperate commits).
Diffstat (limited to 'src')
-rw-r--r--src/libcore/iter.rs41
-rw-r--r--src/libcore/option.rs8
-rw-r--r--src/libcoretest/iter.rs17
-rw-r--r--src/libcoretest/option.rs33
4 files changed, 86 insertions, 13 deletions
diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs
index 93d8d7d6e48..3b62c8da1eb 100644
--- a/src/libcore/iter.rs
+++ b/src/libcore/iter.rs
@@ -65,9 +65,10 @@ use cmp;
 use cmp::Ord;
 use mem;
 use num::{ToPrimitive, Int};
-use ops::Add;
+use ops::{Add, Deref};
 use option::{Option, Some, None};
 use uint;
+
 #[deprecated = "renamed to Extend"] pub use self::Extend as Extendable;
 
 /// Conversion from an `Iterator`
@@ -1021,6 +1022,44 @@ impl<T: Clone> MinMaxResult<T> {
     }
 }
 
+/// A trait for iterators that contain cloneable elements
+pub trait CloneIteratorExt<A> {
+    /// Creates an iterator that clones the elements it yields. Useful for converting an
+    /// Iterator<&T> to an Iterator<T>.
+    fn cloned(self) -> Cloned<Self>;
+}
+
+
+impl<A: Clone, D: Deref<A>, I: Iterator<D>> CloneIteratorExt<A> for I {
+    fn cloned(self) -> Cloned<I> {
+        Cloned { it: self }
+    }
+}
+
+/// An iterator that clones the elements of an underlying iterator
+pub struct Cloned<I> {
+    it: I,
+}
+
+impl<A: Clone, D: Deref<A>, I: Iterator<D>> Iterator<A> for Cloned<I> {
+    fn next(&mut self) -> Option<A> {
+        self.it.next().cloned()
+    }
+
+    fn size_hint(&self) -> (uint, Option<uint>) {
+        self.it.size_hint()
+    }
+}
+
+impl<A: Clone, D: Deref<A>, I: DoubleEndedIterator<D>>
+        DoubleEndedIterator<A> for Cloned<I> {
+    fn next_back(&mut self) -> Option<A> {
+        self.it.next_back().cloned()
+    }
+}
+
+impl<A: Clone, D: Deref<A>, I: ExactSize<D>> ExactSize<A> for Cloned<I> {}
+
 /// A trait for iterators that are cloneable.
 pub trait CloneableIterator {
     /// Repeats an iterator endlessly
diff --git a/src/libcore/option.rs b/src/libcore/option.rs
index 5b1590518f8..19938973037 100644
--- a/src/libcore/option.rs
+++ b/src/libcore/option.rs
@@ -153,6 +153,7 @@ use result::{Result, Ok, Err};
 use slice;
 use slice::AsSlice;
 use clone::Clone;
+use ops::Deref;
 
 // Note that this is not a lang item per se, but it has a hidden dependency on
 // `Iterator`, which is one. The compiler assumes that the `next` method of
@@ -694,11 +695,12 @@ impl<T> Option<T> {
     }
 }
 
-impl<'a, T: Clone> Option<&'a T> {
-    /// Maps an Option<&T> to an Option<T> by cloning the contents of the Option<&T>.
+impl<'a, T: Clone, D: Deref<T>> Option<D> {
+    /// Maps an Option<D> to an Option<T> by dereffing and cloning the contents of the Option.
+    /// Useful for converting an Option<&T> to an Option<T>.
     #[unstable = "recently added as part of collections reform"]
     pub fn cloned(self) -> Option<T> {
-        self.map(|t| t.clone())
+        self.map(|t| t.deref().clone())
     }
 }
 
diff --git a/src/libcoretest/iter.rs b/src/libcoretest/iter.rs
index 32aff498ba1..d046faa82d4 100644
--- a/src/libcoretest/iter.rs
+++ b/src/libcoretest/iter.rs
@@ -441,6 +441,23 @@ fn test_rev() {
 }
 
 #[test]
+fn test_cloned() {
+    let xs = [2u8, 4, 6, 8];
+
+    let mut it = xs.iter().cloned();
+    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_double_ended_map() {
     let xs = [1i, 2, 3, 4, 5, 6];
     let mut it = xs.iter().map(|&x| x * -1);
diff --git a/src/libcoretest/option.rs b/src/libcoretest/option.rs
index 6138986e1d1..a5927d47eb0 100644
--- a/src/libcoretest/option.rs
+++ b/src/libcoretest/option.rs
@@ -241,14 +241,29 @@ fn test_collect() {
     assert!(v == None);
 }
 
+#[test]
 fn test_cloned() {
-    let s = 1u32;
-    let n: Option<&'static u32> = None;
-    let o = Some(&s);
-
-    assert_eq!(o.clone(), Some(&s));
-    assert_eq!(o.cloned(), Some(1u32));
-
-    assert_eq!(n.clone(), None);
-    assert_eq!(n.cloned(), None);
+    let val1 = 1u32;
+    let mut val2 = 2u32;
+    let val1_ref = &val1;
+    let opt_none: Option<&'static u32> = None;
+    let opt_ref = Some(&val1);
+    let opt_ref_ref = Some(&val1_ref);
+    let opt_mut_ref = Some(&mut val2);
+
+    // None works
+    assert_eq!(opt_none.clone(), None);
+    assert_eq!(opt_none.cloned(), None);
+
+    // Mutable refs work
+    assert_eq!(opt_mut_ref.cloned(), Some(2u32));
+
+    // Immutable ref works
+    assert_eq!(opt_ref.clone(), Some(&val1));
+    assert_eq!(opt_ref.cloned(), Some(1u32));
+
+    // Double Immutable ref works
+    assert_eq!(opt_ref_ref.clone(), Some(&val1_ref));
+    assert_eq!(opt_ref_ref.clone().cloned(), Some(&val1));
+    assert_eq!(opt_ref_ref.cloned().cloned(), Some(1u32));
 }
\ No newline at end of file