From 705383adb037dddd834970d2c10edb32dae9fa56 Mon Sep 17 00:00:00 2001 From: Konrad Borowski Date: Wed, 5 Dec 2018 14:39:36 +0100 Subject: [PATCH 1/9] Add unstable Option::copied() --- src/libcore/option.rs | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/src/libcore/option.rs b/src/libcore/option.rs index cf1c77041b91f..67bed63e6ff08 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 = "0")] + 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 = "0")] + 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. From ab2cd6070e73dc79a5b5e0b67cad120f0ccb4217 Mon Sep 17 00:00:00 2001 From: Konrad Borowski Date: Wed, 5 Dec 2018 14:39:42 +0100 Subject: [PATCH 2/9] Add unstable Iterator::copied() --- src/libcore/iter/iterator.rs | 31 +++++++++++- src/libcore/iter/mod.rs | 98 ++++++++++++++++++++++++++++++++++++ 2 files changed, 128 insertions(+), 1 deletion(-) diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index 3063cb1a7df44..80bd5698c4726 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}; @@ -2234,6 +2234,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 = "0")] + 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 62e1f9fcb640c..a23a404e3788b 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -501,6 +501,104 @@ 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 = "0")] +#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] +#[derive(Clone, Debug)] +pub struct Copied { + it: I, +} + +#[unstable(feature = "iter_copied", issue = "0")] +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 = "0")] +impl<'a, I, T: 'a> DoubleEndedIterator for Copied + where I: DoubleEndedIterator, T: Copy +{ + fn next_back(&mut self) -> Option { + self.it.next_back().cloned() + } + + 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.clone())) + } + + 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.clone())) + } +} + +#[unstable(feature = "iter_copied", issue = "0")] +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 = "0")] +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 { false } +} + +#[unstable(feature = "iter_copied", issue = "0")] +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 From fcc46040a969f48cef92582bc78c792edb90ff8c Mon Sep 17 00:00:00 2001 From: Konrad Borowski Date: Wed, 5 Dec 2018 14:52:23 +0100 Subject: [PATCH 3/9] Add tests for Option::copied() --- src/libcore/tests/lib.rs | 1 + src/libcore/tests/option.rs | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 7d62b4fa90f20..58b5ea7ff2d41 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)] 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() { From fe45e9a886763e60c2078684bdbab08bceeee9e6 Mon Sep 17 00:00:00 2001 From: Konrad Borowski Date: Wed, 5 Dec 2018 14:52:38 +0100 Subject: [PATCH 4/9] Add tests for Iterator::copied() --- src/libcore/tests/iter.rs | 17 +++++++++++++++++ src/libcore/tests/lib.rs | 1 + 2 files changed, 18 insertions(+) diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index 495483db5551c..0964aae1db575 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -1232,6 +1232,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 58b5ea7ff2d41..1f7a8b774d787 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -20,6 +20,7 @@ #![feature(flt2dec)] #![feature(fmt_internals)] #![feature(hashmap_internals)] +#![feature(iter_copied)] #![feature(iter_unfold)] #![feature(pattern)] #![feature(range_is_empty)] From 3ee0747b5a88ea573c32de164ba48e191a0a351c Mon Sep 17 00:00:00 2001 From: Konrad Borowski Date: Wed, 5 Dec 2018 16:37:55 +0100 Subject: [PATCH 5/9] Use copied method instead of cloned in Copied::next_back() --- src/libcore/iter/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index a23a404e3788b..44fe16a250883 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -547,7 +547,7 @@ impl<'a, I, T: 'a> DoubleEndedIterator for Copied where I: DoubleEndedIterator, T: Copy { fn next_back(&mut self) -> Option { - self.it.next_back().cloned() + self.it.next_back().copied() } fn try_rfold(&mut self, init: B, mut f: F) -> R where From 431968df376ae24347872ba3986c4c3efd29d41e Mon Sep 17 00:00:00 2001 From: Konrad Borowski Date: Wed, 5 Dec 2018 16:42:20 +0100 Subject: [PATCH 6/9] Copy may_have_side_effect from I for Copied --- src/libcore/iter/mod.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index 44fe16a250883..be09182c01aac 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -590,7 +590,9 @@ unsafe impl<'a, I, T: 'a> TrustedRandomAccess for Copied } #[inline] - fn may_have_side_effect() -> bool { false } + fn may_have_side_effect() -> bool { + I::may_have_side_effect() + } } #[unstable(feature = "iter_copied", issue = "0")] From b4a306c1e648c84f289c63e984941b7faad10af1 Mon Sep 17 00:00:00 2001 From: Konrad Borowski Date: Wed, 5 Dec 2018 17:55:53 +0100 Subject: [PATCH 7/9] Avoid calling clone in DoubleEndedIterator implementation of Copied --- src/libcore/iter/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index be09182c01aac..de1a318cfb220 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -553,13 +553,13 @@ impl<'a, I, T: 'a> DoubleEndedIterator for 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.clone())) + 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.clone())) + self.it.rfold(init, move |acc, &elt| f(acc, elt)) } } From 2fcdc9c15d553e48e1cd8b3547f4ce3016771e94 Mon Sep 17 00:00:00 2001 From: Konrad Borowski Date: Wed, 26 Dec 2018 10:13:02 +0100 Subject: [PATCH 8/9] Add a tracking issue for Option::copied --- src/libcore/option.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 3147b21f86b63..9db7e47b08cfa 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -899,7 +899,7 @@ impl<'a, T: Copy> Option<&'a T> { /// let copied = opt_x.copied(); /// assert_eq!(copied, Some(12)); /// ``` - #[unstable(feature = "copied", issue = "0")] + #[unstable(feature = "copied", issue = "57126")] pub fn copied(self) -> Option { self.map(|&t| t) } @@ -920,7 +920,7 @@ impl<'a, T: Copy> Option<&'a mut T> { /// let copied = opt_x.copied(); /// assert_eq!(copied, Some(12)); /// ``` - #[unstable(feature = "copied", issue = "0")] + #[unstable(feature = "copied", issue = "57126")] pub fn copied(self) -> Option { self.map(|&mut t| t) } From 315401ddf8857c9431a889ac1307dca856e4fe65 Mon Sep 17 00:00:00 2001 From: Konrad Borowski Date: Wed, 26 Dec 2018 10:13:44 +0100 Subject: [PATCH 9/9] Add a tracking issue for Iterator::copied --- src/libcore/iter/iterator.rs | 2 +- src/libcore/iter/mod.rs | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index d0b0fd1ab3171..dab6241504f69 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/iterator.rs @@ -2257,7 +2257,7 @@ pub trait Iterator { /// assert_eq!(v_cloned, vec![1, 2, 3]); /// assert_eq!(v_map, vec![1, 2, 3]); /// ``` - #[unstable(feature = "iter_copied", issue = "0")] + #[unstable(feature = "iter_copied", issue = "57127")] fn copied<'a, T: 'a>(self) -> Copied where Self: Sized + Iterator, T: Copy { diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index aa130754f8304..34c84d90e37c5 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -514,14 +514,14 @@ unsafe impl TrustedLen for Rev /// /// [`copied`]: trait.Iterator.html#method.copied /// [`Iterator`]: trait.Iterator.html -#[unstable(feature = "iter_copied", issue = "0")] +#[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 = "0")] +#[unstable(feature = "iter_copied", issue = "57127")] impl<'a, I, T: 'a> Iterator for Copied where I: Iterator, T: Copy { @@ -548,7 +548,7 @@ impl<'a, I, T: 'a> Iterator for Copied } } -#[unstable(feature = "iter_copied", issue = "0")] +#[unstable(feature = "iter_copied", issue = "57127")] impl<'a, I, T: 'a> DoubleEndedIterator for Copied where I: DoubleEndedIterator, T: Copy { @@ -569,7 +569,7 @@ impl<'a, I, T: 'a> DoubleEndedIterator for Copied } } -#[unstable(feature = "iter_copied", issue = "0")] +#[unstable(feature = "iter_copied", issue = "57127")] impl<'a, I, T: 'a> ExactSizeIterator for Copied where I: ExactSizeIterator, T: Copy { @@ -582,7 +582,7 @@ impl<'a, I, T: 'a> ExactSizeIterator for Copied } } -#[unstable(feature = "iter_copied", issue = "0")] +#[unstable(feature = "iter_copied", issue = "57127")] impl<'a, I, T: 'a> FusedIterator for Copied where I: FusedIterator, T: Copy {} @@ -601,7 +601,7 @@ unsafe impl<'a, I, T: 'a> TrustedRandomAccess for Copied } } -#[unstable(feature = "iter_copied", issue = "0")] +#[unstable(feature = "iter_copied", issue = "57127")] unsafe impl<'a, I, T: 'a> TrustedLen for Copied where I: TrustedLen, T: Copy