From 19d40e1910a2134edc6232ed06112991811d7ca6 Mon Sep 17 00:00:00 2001 From: Ulrik Sverdrup Date: Mon, 7 Aug 2017 19:07:08 +0200 Subject: [PATCH] core: Allow unsized closures in iterator adaptors For example, `Map` can be generalized to `Map`, which allows for example the type `Map Bar>` as an iterator. Generalize `filter, filter_map, flat_map, inspect, map, skip_while, take_while` like this. A struct can only have one unsizeable field, so we have to pick either unsizing the iterator or closure parameter for all of these, but it seems right to pick the closure parameter. The whole struct itself can already coerce to the `Iterator` type. --- src/libcore/iter/mod.rs | 89 +++++++++++++++++++++------------------ src/libcore/tests/iter.rs | 13 ++++++ 2 files changed, 60 insertions(+), 42 deletions(-) diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index 79e6b11beaca6..f506b8a967b5c 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -1050,13 +1050,13 @@ unsafe impl TrustedLen for Zip #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] #[stable(feature = "rust1", since = "1.0.0")] #[derive(Clone)] -pub struct Map { +pub struct Map { iter: I, f: F, } #[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for Map { +impl fmt::Debug for Map { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Map") .field("iter", &self.iter) @@ -1065,7 +1065,8 @@ impl fmt::Debug for Map { } #[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for Map where F: FnMut(I::Item) -> B { +impl Iterator for Map where F: FnMut(I::Item) -> B +{ type Item = B; #[inline] @@ -1078,16 +1079,17 @@ impl Iterator for Map where F: FnMut(I::Item) -> B { self.iter.size_hint() } - fn fold(self, init: Acc, mut g: G) -> Acc + fn fold(mut self, init: Acc, mut g: G) -> Acc where G: FnMut(Acc, Self::Item) -> Acc, + Self: Sized, { - let mut f = self.f; + let f = &mut self.f; self.iter.fold(init, move |acc, elt| g(acc, f(elt))) } } #[stable(feature = "rust1", since = "1.0.0")] -impl DoubleEndedIterator for Map where +impl DoubleEndedIterator for Map where F: FnMut(I::Item) -> B, { #[inline] @@ -1097,7 +1099,7 @@ impl DoubleEndedIterator for Map where } #[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for Map +impl ExactSizeIterator for Map where F: FnMut(I::Item) -> B { fn len(&self) -> usize { @@ -1110,16 +1112,16 @@ impl ExactSizeIterator for Map } #[unstable(feature = "fused", issue = "35602")] -impl FusedIterator for Map +impl FusedIterator for Map where F: FnMut(I::Item) -> B {} #[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for Map +unsafe impl TrustedLen for Map where I: TrustedLen, F: FnMut(I::Item) -> B {} #[doc(hidden)] -unsafe impl TrustedRandomAccess for Map +unsafe impl TrustedRandomAccess for Map where I: TrustedRandomAccess, F: FnMut(I::Item) -> B, { @@ -1140,13 +1142,13 @@ unsafe impl TrustedRandomAccess for Map #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] #[stable(feature = "rust1", since = "1.0.0")] #[derive(Clone)] -pub struct Filter { +pub struct Filter { iter: I, predicate: P, } #[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for Filter { +impl fmt::Debug for Filter { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Filter") .field("iter", &self.iter) @@ -1155,7 +1157,8 @@ impl fmt::Debug for Filter { } #[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for Filter where P: FnMut(&I::Item) -> bool { +impl Iterator for Filter where P: FnMut(&I::Item) -> bool +{ type Item = I::Item; #[inline] @@ -1186,7 +1189,9 @@ impl Iterator for Filter where P: FnMut(&I::Item) -> bool // Using the branchless version will also simplify the LLVM byte code, thus // leaving more budget for LLVM optimizations. #[inline] - fn count(mut self) -> usize { + fn count(mut self) -> usize + where Self: Sized + { let mut count = 0; for x in &mut self.iter { count += (self.predicate)(&x) as usize; @@ -1196,7 +1201,7 @@ impl Iterator for Filter where P: FnMut(&I::Item) -> bool } #[stable(feature = "rust1", since = "1.0.0")] -impl DoubleEndedIterator for Filter +impl DoubleEndedIterator for Filter where P: FnMut(&I::Item) -> bool, { #[inline] @@ -1211,7 +1216,7 @@ impl DoubleEndedIterator for Filter } #[unstable(feature = "fused", issue = "35602")] -impl FusedIterator for Filter +impl FusedIterator for Filter where P: FnMut(&I::Item) -> bool {} /// An iterator that uses `f` to both filter and map elements from `iter`. @@ -1224,13 +1229,13 @@ impl FusedIterator for Filter #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] #[stable(feature = "rust1", since = "1.0.0")] #[derive(Clone)] -pub struct FilterMap { +pub struct FilterMap { iter: I, f: F, } #[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for FilterMap { +impl fmt::Debug for FilterMap { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("FilterMap") .field("iter", &self.iter) @@ -1239,7 +1244,7 @@ impl fmt::Debug for FilterMap { } #[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for FilterMap +impl Iterator for FilterMap where F: FnMut(I::Item) -> Option, { type Item = B; @@ -1262,7 +1267,7 @@ impl Iterator for FilterMap } #[stable(feature = "rust1", since = "1.0.0")] -impl DoubleEndedIterator for FilterMap +impl DoubleEndedIterator for FilterMap where F: FnMut(I::Item) -> Option, { #[inline] @@ -1277,7 +1282,7 @@ impl DoubleEndedIterator for FilterMap } #[unstable(feature = "fused", issue = "35602")] -impl FusedIterator for FilterMap +impl FusedIterator for FilterMap where F: FnMut(I::Item) -> Option {} /// An iterator that yields the current count and the element during iteration. @@ -1534,14 +1539,14 @@ impl Peekable { #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] #[stable(feature = "rust1", since = "1.0.0")] #[derive(Clone)] -pub struct SkipWhile { +pub struct SkipWhile { iter: I, flag: bool, predicate: P, } #[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for SkipWhile { +impl fmt::Debug for SkipWhile { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("SkipWhile") .field("iter", &self.iter) @@ -1551,7 +1556,7 @@ impl fmt::Debug for SkipWhile { } #[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for SkipWhile +impl Iterator for SkipWhile where P: FnMut(&I::Item) -> bool { type Item = I::Item; @@ -1575,7 +1580,7 @@ impl Iterator for SkipWhile } #[unstable(feature = "fused", issue = "35602")] -impl FusedIterator for SkipWhile +impl FusedIterator for SkipWhile where I: FusedIterator, P: FnMut(&I::Item) -> bool {} /// An iterator that only accepts elements while `predicate` is true. @@ -1588,14 +1593,14 @@ impl FusedIterator for SkipWhile #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] #[stable(feature = "rust1", since = "1.0.0")] #[derive(Clone)] -pub struct TakeWhile { +pub struct TakeWhile { iter: I, flag: bool, predicate: P, } #[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for TakeWhile { +impl fmt::Debug for TakeWhile { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("TakeWhile") .field("iter", &self.iter) @@ -1605,7 +1610,7 @@ impl fmt::Debug for TakeWhile { } #[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for TakeWhile +impl Iterator for TakeWhile where P: FnMut(&I::Item) -> bool { type Item = I::Item; @@ -1634,7 +1639,7 @@ impl Iterator for TakeWhile } #[unstable(feature = "fused", issue = "35602")] -impl FusedIterator for TakeWhile +impl FusedIterator for TakeWhile where I: FusedIterator, P: FnMut(&I::Item) -> bool {} /// An iterator that skips over `n` elements of `iter`. @@ -1851,15 +1856,15 @@ impl Iterator for Scan where #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] #[stable(feature = "rust1", since = "1.0.0")] #[derive(Clone)] -pub struct FlatMap { +pub struct FlatMap { iter: I, - f: F, frontiter: Option, backiter: Option, + f: F, } #[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for FlatMap +impl fmt::Debug for FlatMap where U::IntoIter: fmt::Debug { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -1872,7 +1877,7 @@ impl fmt::Debug for FlatMap } #[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for FlatMap +impl Iterator for FlatMap where F: FnMut(I::Item) -> U, { type Item = U::Item; @@ -1905,7 +1910,7 @@ impl Iterator for FlatMap } #[stable(feature = "rust1", since = "1.0.0")] -impl DoubleEndedIterator for FlatMap where +impl DoubleEndedIterator for FlatMap where F: FnMut(I::Item) -> U, U: IntoIterator, U::IntoIter: DoubleEndedIterator @@ -1927,7 +1932,7 @@ impl DoubleEndedIterator for FlatMap wher } #[unstable(feature = "fused", issue = "35602")] -impl FusedIterator for FlatMap +impl FusedIterator for FlatMap where I: FusedIterator, U: IntoIterator, F: FnMut(I::Item) -> U {} /// An iterator that yields `None` forever after the underlying iterator @@ -2090,13 +2095,13 @@ impl ExactSizeIterator for Fuse where I: ExactSizeIterator { #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] #[stable(feature = "rust1", since = "1.0.0")] #[derive(Clone)] -pub struct Inspect { +pub struct Inspect { iter: I, f: F, } #[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for Inspect { +impl fmt::Debug for Inspect { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Inspect") .field("iter", &self.iter) @@ -2104,7 +2109,7 @@ impl fmt::Debug for Inspect { } } -impl Inspect where F: FnMut(&I::Item) { +impl Inspect where F: FnMut(&I::Item) { #[inline] fn do_inspect(&mut self, elt: Option) -> Option { if let Some(ref a) = elt { @@ -2116,7 +2121,7 @@ impl Inspect where F: FnMut(&I::Item) { } #[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for Inspect where F: FnMut(&I::Item) { +impl Iterator for Inspect where F: FnMut(&I::Item) { type Item = I::Item; #[inline] @@ -2132,7 +2137,7 @@ impl Iterator for Inspect where F: FnMut(&I::Item) { } #[stable(feature = "rust1", since = "1.0.0")] -impl DoubleEndedIterator for Inspect +impl DoubleEndedIterator for Inspect where F: FnMut(&I::Item), { #[inline] @@ -2143,7 +2148,7 @@ impl DoubleEndedIterator for Inspect } #[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for Inspect +impl ExactSizeIterator for Inspect where F: FnMut(&I::Item) { fn len(&self) -> usize { @@ -2156,5 +2161,5 @@ impl ExactSizeIterator for Inspect } #[unstable(feature = "fused", issue = "35602")] -impl FusedIterator for Inspect +impl FusedIterator for Inspect where F: FnMut(&I::Item) {} diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index a1249a5f22cf7..91d201ed633ab 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -1288,3 +1288,16 @@ fn test_step_replace_no_between() { assert_eq!(x, 1); assert_eq!(y, 5); } + +#[test] +fn test_unsized_closures_in_map_etc() { + fn an_iterator(iter: &mut I) { let _ = iter.next(); } + + an_iterator:: _>>(&mut (0..10).filter(|_| true)); + an_iterator:: _>>(&mut (0..10).filter_map(|i| Some(i))); + an_iterator:: _>>(&mut (0..10).flat_map(|i| 0..i)); + an_iterator::>(&mut (0..10).inspect(|_| {})); + an_iterator:: _>>(&mut (0..10).map(|x| x + 1)); + an_iterator:: _>>(&mut (0..10).skip_while(|_| true)); + an_iterator:: _>>(&mut (0..10).take_while(|_| true)); +}