diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index f77d8eb6f7c55..dab6241504f69 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/iterator.rs @@ -12,7 +12,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}; @@ -2235,6 +2235,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 + where Self: Sized + Iterator, 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 e493a3804376f..34c84d90e37c5 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -507,6 +507,106 @@ impl FusedIterator for Rev unsafe impl TrustedLen for Rev 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 { + it: I, +} + +#[unstable(feature = "iter_copied", issue = "57127")] +impl<'a, I, T: 'a> Iterator for Copied + where I: Iterator, T: Copy +{ + type Item = T; + + fn next(&mut self) -> Option { + self.it.next().copied() + } + + fn size_hint(&self) -> (usize, Option) { + self.it.size_hint() + } + + fn try_fold(&mut self, init: B, mut f: F) -> R where + Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try + { + self.it.try_fold(init, move |acc, &elt| f(acc, elt)) + } + + fn fold(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 + where I: DoubleEndedIterator, T: Copy +{ + fn next_back(&mut self) -> Option { + self.it.next_back().copied() + } + + fn try_rfold(&mut self, init: B, mut f: F) -> R where + Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try + { + self.it.try_rfold(init, move |acc, &elt| f(acc, elt)) + } + + fn rfold(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 + where I: ExactSizeIterator, 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 + where I: FusedIterator, T: Copy +{} + +#[doc(hidden)] +unsafe impl<'a, I, T: 'a> TrustedRandomAccess for Copied + where I: TrustedRandomAccess, 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 + where I: TrustedLen, + 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 44d632ece055c..9db7e47b08cfa 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -884,6 +884,48 @@ impl Option { } } +impl<'a, T: Copy> Option<&'a T> { + /// Maps an `Option<&T>` to an `Option` 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 { + self.map(|&t| t) + } +} + +impl<'a, T: Copy> Option<&'a mut T> { + /// Maps an `Option<&mut T>` to an `Option` 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 { + self.map(|&mut t| t) + } +} + impl<'a, T: Clone> Option<&'a T> { /// Maps an `Option<&T>` to an `Option` by cloning the contents of the /// option. diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index b5633333d0170..44899c3f41244 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -1263,6 +1263,23 @@ fn test_rev() { vec![16, 14, 12, 10, 8, 6]); } +#[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 2377a4733678d..400a86d2ffe0e 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -10,6 +10,7 @@ #![feature(box_syntax)] #![feature(cell_update)] +#![feature(copied)] #![feature(core_private_bignum)] #![feature(core_private_diy_float)] #![feature(dec2flt)] @@ -19,6 +20,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 1324ba2d9a9c3..b4761f8942659 100644 --- a/src/libcore/tests/option.rs +++ b/src/libcore/tests/option.rs @@ -248,6 +248,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() {