diff options
| author | bors <bors@rust-lang.org> | 2014-11-18 17:21:43 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2014-11-18 17:21:43 +0000 |
| commit | 09e2ad13d0aa01143bcb20dece3ff6c5a7e34ea3 (patch) | |
| tree | 2e0ccae2ab9d6cb5871429279a673c0e4a3f2069 /src | |
| parent | 618bd5d1c550cbdaac369b01716cc009b9e4d1e7 (diff) | |
| parent | 4a656062eeca015739015a327192dc067bfb1428 (diff) | |
| download | rust-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.rs | 41 | ||||
| -rw-r--r-- | src/libcore/option.rs | 8 | ||||
| -rw-r--r-- | src/libcoretest/iter.rs | 17 | ||||
| -rw-r--r-- | src/libcoretest/option.rs | 33 |
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 |
