diff --git a/src/adaptors/mod.rs b/src/adaptors/mod.rs index 127edaa56..79188ccb5 100644 --- a/src/adaptors/mod.rs +++ b/src/adaptors/mod.rs @@ -24,6 +24,52 @@ macro_rules! clone_fields { } ); } +/// An iterator that copies the elements of an underlying iterator. +/// +/// See [`.copied()`](../trait.Itertools.html#method.copied) for more information. +#[derive(Clone, Debug)] +#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] +pub struct Copied { + it: I +} + +pub fn copied<'a, I, T>(iterable: I) -> Copied + where I: IntoIterator, + T: 'a + Copy +{ + Copied { it: iterable.into_iter() } +} + +impl<'a, I, T> Iterator for Copied + where I: Iterator, + T: Copy + 'a +{ + type Item = T; + #[inline] + fn next(&mut self) -> Option { + self.it.next().map(|&x| x) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.it.size_hint() + } +} + +impl<'a, I, T> ExactSizeIterator for Copied + where I: ExactSizeIterator, + T: Copy + 'a +{} + +impl<'a, I, T> DoubleEndedIterator for Copied + where I: DoubleEndedIterator, + T: Copy + 'a +{ + #[inline] + fn next_back(&mut self) -> Option { + self.it.next_back().map(|&x| x) + } +} /// An iterator adaptor that alternates elements from two iterators until both /// run out. diff --git a/src/lib.rs b/src/lib.rs index e4671921c..e7cdedaf7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -51,6 +51,7 @@ pub use std::iter as __std_iter; /// The concrete iterator types. pub mod structs { pub use adaptors::{ + Copied, Dedup, Interleave, InterleaveShortest, @@ -1983,6 +1984,33 @@ pub trait Itertools : Iterator { |x, y, _, _| Ordering::Less == compare(x, y) ) } + + /// 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`. It works like `Iterator::cloned`, but requires + /// `T` to implement `Copy`. + /// + /// # Examples + /// + /// ``` + /// use itertools::Itertools; + /// + /// let a = [1, 2, 3]; + /// + /// let v_copied: 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_copied, vec![1, 2, 3]); + /// assert_eq!(v_map, vec![1, 2, 3]); + /// ``` + fn copied<'a, T>(self) -> Copied + where Self: Sized + Iterator, T: 'a + Copy + { + adaptors::copied(self) + } } impl Itertools for T where T: Iterator { } diff --git a/tests/test_core.rs b/tests/test_core.rs index e21525501..c1315570a 100644 --- a/tests/test_core.rs +++ b/tests/test_core.rs @@ -75,7 +75,7 @@ fn izip3() { fn write_to() { let xs = [7, 9, 8]; let mut ys = [0; 5]; - let cnt = ys.iter_mut().set_from(xs.iter().map(|x| *x)); + let cnt = ys.iter_mut().set_from(xs.iter().copied()); assert!(cnt == xs.len()); assert!(ys == [7, 9, 8, 0, 0]); @@ -238,3 +238,12 @@ fn tree_fold1() { assert_eq!((0..i).tree_fold1(|x, y| x + y), (0..i).fold1(|x, y| x + y)); } } + +#[test] +fn test_copied() { + let a = [1, 2, 3, 4, 5]; + let mut copied = a.iter().copied(); + assert_eq!(copied.next(), Some(1)); + assert_eq!(copied.next_back(), Some(5)); + it::assert_equal(copied, [2, 3, 4].iter().cloned()); +}