Reduce the genericity of Map folds

This commit is contained in:
Josh Stone 2019-07-08 16:16:24 -07:00
parent 755c091b71
commit 0e300e4380
2 changed files with 59 additions and 12 deletions

View file

@ -594,6 +594,20 @@ impl<I: fmt::Debug, F> fmt::Debug for Map<I, F> {
}
}
fn map_fold<T, B, Acc>(
mut f: impl FnMut(T) -> B,
mut g: impl FnMut(Acc, B) -> Acc,
) -> impl FnMut(Acc, T) -> Acc {
move |acc, elt| g(acc, f(elt))
}
fn map_try_fold<'a, T, B, Acc, R>(
f: &'a mut impl FnMut(T) -> B,
mut g: impl FnMut(Acc, B) -> R + 'a,
) -> impl FnMut(Acc, T) -> R + 'a {
move |acc, elt| g(acc, f(elt))
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<B, I: Iterator, F> Iterator for Map<I, F> where F: FnMut(I::Item) -> B {
type Item = B;
@ -608,18 +622,16 @@ impl<B, I: Iterator, F> Iterator for Map<I, F> where F: FnMut(I::Item) -> B {
self.iter.size_hint()
}
fn try_fold<Acc, G, R>(&mut self, init: Acc, mut g: G) -> R where
fn try_fold<Acc, G, R>(&mut self, init: Acc, g: G) -> R where
Self: Sized, G: FnMut(Acc, Self::Item) -> R, R: Try<Ok=Acc>
{
let f = &mut self.f;
self.iter.try_fold(init, move |acc, elt| g(acc, f(elt)))
self.iter.try_fold(init, map_try_fold(&mut self.f, g))
}
fn fold<Acc, G>(self, init: Acc, mut g: G) -> Acc
fn fold<Acc, G>(self, init: Acc, g: G) -> Acc
where G: FnMut(Acc, Self::Item) -> Acc,
{
let mut f = self.f;
self.iter.fold(init, move |acc, elt| g(acc, f(elt)))
self.iter.fold(init, map_fold(self.f, g))
}
}
@ -632,18 +644,16 @@ impl<B, I: DoubleEndedIterator, F> DoubleEndedIterator for Map<I, F> where
self.iter.next_back().map(&mut self.f)
}
fn try_rfold<Acc, G, R>(&mut self, init: Acc, mut g: G) -> R where
fn try_rfold<Acc, G, R>(&mut self, init: Acc, g: G) -> R where
Self: Sized, G: FnMut(Acc, Self::Item) -> R, R: Try<Ok=Acc>
{
let f = &mut self.f;
self.iter.try_rfold(init, move |acc, elt| g(acc, f(elt)))
self.iter.try_rfold(init, map_try_fold(&mut self.f, g))
}
fn rfold<Acc, G>(self, init: Acc, mut g: G) -> Acc
fn rfold<Acc, G>(self, init: Acc, g: G) -> Acc
where G: FnMut(Acc, Self::Item) -> Acc,
{
let mut f = self.f;
self.iter.rfold(init, move |acc, elt| g(acc, f(elt)))
self.iter.rfold(init, map_fold(self.f, g))
}
}

View file

@ -0,0 +1,37 @@
//! Check that type lengths don't explode with `Map` folds.
//!
//! The normal limit is a million, and this test used to exceed 1.5 million, but
//! now we can survive an even tighter limit. Still seems excessive though...
#![type_length_limit = "256000"]
// Custom wrapper so Iterator methods aren't specialized.
struct Iter<I>(I);
impl<I> Iterator for Iter<I>
where
I: Iterator
{
type Item = I::Item;
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
}
fn main() {
let c = Iter(0i32..10)
.map(|x| x)
.map(|x| x)
.map(|x| x)
.map(|x| x)
.map(|x| x)
.map(|x| x)
.map(|x| x)
.map(|x| x)
.map(|x| x)
.map(|x| x)
.map(|x| x)
.map(|x| x)
.count();
assert_eq!(c, 10);
}