Skip to content

Commit 09e2ad1

Browse files
committed
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! 🎉 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).
2 parents 618bd5d + 4a65606 commit 09e2ad1

File tree

4 files changed

+86
-13
lines changed

4 files changed

+86
-13
lines changed

src/libcore/iter.rs

+40-1
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,10 @@ use cmp;
6565
use cmp::Ord;
6666
use mem;
6767
use num::{ToPrimitive, Int};
68-
use ops::Add;
68+
use ops::{Add, Deref};
6969
use option::{Option, Some, None};
7070
use uint;
71+
7172
#[deprecated = "renamed to Extend"] pub use self::Extend as Extendable;
7273

7374
/// Conversion from an `Iterator`
@@ -1021,6 +1022,44 @@ impl<T: Clone> MinMaxResult<T> {
10211022
}
10221023
}
10231024

1025+
/// A trait for iterators that contain cloneable elements
1026+
pub trait CloneIteratorExt<A> {
1027+
/// Creates an iterator that clones the elements it yields. Useful for converting an
1028+
/// Iterator<&T> to an Iterator<T>.
1029+
fn cloned(self) -> Cloned<Self>;
1030+
}
1031+
1032+
1033+
impl<A: Clone, D: Deref<A>, I: Iterator<D>> CloneIteratorExt<A> for I {
1034+
fn cloned(self) -> Cloned<I> {
1035+
Cloned { it: self }
1036+
}
1037+
}
1038+
1039+
/// An iterator that clones the elements of an underlying iterator
1040+
pub struct Cloned<I> {
1041+
it: I,
1042+
}
1043+
1044+
impl<A: Clone, D: Deref<A>, I: Iterator<D>> Iterator<A> for Cloned<I> {
1045+
fn next(&mut self) -> Option<A> {
1046+
self.it.next().cloned()
1047+
}
1048+
1049+
fn size_hint(&self) -> (uint, Option<uint>) {
1050+
self.it.size_hint()
1051+
}
1052+
}
1053+
1054+
impl<A: Clone, D: Deref<A>, I: DoubleEndedIterator<D>>
1055+
DoubleEndedIterator<A> for Cloned<I> {
1056+
fn next_back(&mut self) -> Option<A> {
1057+
self.it.next_back().cloned()
1058+
}
1059+
}
1060+
1061+
impl<A: Clone, D: Deref<A>, I: ExactSize<D>> ExactSize<A> for Cloned<I> {}
1062+
10241063
/// A trait for iterators that are cloneable.
10251064
pub trait CloneableIterator {
10261065
/// Repeats an iterator endlessly

src/libcore/option.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ use result::{Result, Ok, Err};
153153
use slice;
154154
use slice::AsSlice;
155155
use clone::Clone;
156+
use ops::Deref;
156157

157158
// Note that this is not a lang item per se, but it has a hidden dependency on
158159
// `Iterator`, which is one. The compiler assumes that the `next` method of
@@ -694,11 +695,12 @@ impl<T> Option<T> {
694695
}
695696
}
696697

697-
impl<'a, T: Clone> Option<&'a T> {
698-
/// Maps an Option<&T> to an Option<T> by cloning the contents of the Option<&T>.
698+
impl<'a, T: Clone, D: Deref<T>> Option<D> {
699+
/// Maps an Option<D> to an Option<T> by dereffing and cloning the contents of the Option.
700+
/// Useful for converting an Option<&T> to an Option<T>.
699701
#[unstable = "recently added as part of collections reform"]
700702
pub fn cloned(self) -> Option<T> {
701-
self.map(|t| t.clone())
703+
self.map(|t| t.deref().clone())
702704
}
703705
}
704706

src/libcoretest/iter.rs

+17
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,23 @@ fn test_rev() {
440440
vec![16, 14, 12, 10, 8, 6]);
441441
}
442442

443+
#[test]
444+
fn test_cloned() {
445+
let xs = [2u8, 4, 6, 8];
446+
447+
let mut it = xs.iter().cloned();
448+
assert_eq!(it.len(), 4);
449+
assert_eq!(it.next(), Some(2));
450+
assert_eq!(it.len(), 3);
451+
assert_eq!(it.next(), Some(4));
452+
assert_eq!(it.len(), 2);
453+
assert_eq!(it.next_back(), Some(8));
454+
assert_eq!(it.len(), 1);
455+
assert_eq!(it.next_back(), Some(6));
456+
assert_eq!(it.len(), 0);
457+
assert_eq!(it.next_back(), None);
458+
}
459+
443460
#[test]
444461
fn test_double_ended_map() {
445462
let xs = [1i, 2, 3, 4, 5, 6];

src/libcoretest/option.rs

+24-9
Original file line numberDiff line numberDiff line change
@@ -241,14 +241,29 @@ fn test_collect() {
241241
assert!(v == None);
242242
}
243243

244+
#[test]
244245
fn test_cloned() {
245-
let s = 1u32;
246-
let n: Option<&'static u32> = None;
247-
let o = Some(&s);
248-
249-
assert_eq!(o.clone(), Some(&s));
250-
assert_eq!(o.cloned(), Some(1u32));
251-
252-
assert_eq!(n.clone(), None);
253-
assert_eq!(n.cloned(), None);
246+
let val1 = 1u32;
247+
let mut val2 = 2u32;
248+
let val1_ref = &val1;
249+
let opt_none: Option<&'static u32> = None;
250+
let opt_ref = Some(&val1);
251+
let opt_ref_ref = Some(&val1_ref);
252+
let opt_mut_ref = Some(&mut val2);
253+
254+
// None works
255+
assert_eq!(opt_none.clone(), None);
256+
assert_eq!(opt_none.cloned(), None);
257+
258+
// Mutable refs work
259+
assert_eq!(opt_mut_ref.cloned(), Some(2u32));
260+
261+
// Immutable ref works
262+
assert_eq!(opt_ref.clone(), Some(&val1));
263+
assert_eq!(opt_ref.cloned(), Some(1u32));
264+
265+
// Double Immutable ref works
266+
assert_eq!(opt_ref_ref.clone(), Some(&val1_ref));
267+
assert_eq!(opt_ref_ref.clone().cloned(), Some(&val1));
268+
assert_eq!(opt_ref_ref.cloned().cloned(), Some(1u32));
254269
}

0 commit comments

Comments
 (0)