use super::{Callback, Consumer, Hide, Split, Spliterator, ExactSizeSpliterator, Zip};
const ZIP_MUL: f32 = 1.2;
struct ZipCallbackA<'a, ConsB: 'a, InB, C> {
consumer_b: &'a ConsB,
in_b: InB,
cb: C
}
struct ZipCallbackB<IterA, C> {
iter: IterA,
cb: C,
}
impl<'a, ItemA, InB, ConsB: 'a, C> Callback<ItemA> for ZipCallbackA<'a, ConsB, InB, C>
where ConsB: Consumer<InB>, InB: IntoIterator,
C: Callback<(ItemA, ConsB::Item)> {
type Out = C::Out;
fn call<I: Iterator<Item=ItemA>>(self, iter: I) -> C::Out {
let b_cb = ZipCallbackB {
iter: iter,
cb: self.cb,
};
self.consumer_b.consume(self.in_b, b_cb)
}
}
impl<ItemA, IterA, C, ItemB> Callback<ItemB> for ZipCallbackB<IterA, C>
where IterA: Iterator<Item=ItemA>, C: Callback<(ItemA, ItemB)> {
type Out = C::Out;
fn call<IterB: Iterator<Item=ItemB>>(self, iter_b: IterB) -> C::Out {
self.cb.call(self.iter.zip(iter_b))
}
}
impl<InA, A, InB, B> Consumer<Hide<Zip<InA, InB>>> for Zip<A, B>
where A: Consumer<InA>, B: Consumer<InB>,
InA: IntoIterator, InB: IntoIterator {
type Item = (A::Item, B::Item);
fn consume<C: Callback<Self::Item>>(&self, i: Hide<Zip<InA, InB>>, cb: C) -> C::Out {
let a_cb = ZipCallbackA {
consumer_b: &self.b,
in_b: i.0.b,
cb: cb,
};
self.a.consume(i.0.a, a_cb)
}
}
impl<A: Spliterator, B: Spliterator> Spliterator for Zip<A, B> {
type Item = (A::Item, B::Item);
type Base = Hide<Zip<A::Base, B::Base>>;
type Consumer = Zip<A::Consumer, B::Consumer>;
fn destructure(self) -> (Self::Base, Self::Consumer) {
let (a_b, a_c) = self.a.destructure();
let (b_b, b_c) = self.b.destructure();
(
Hide(Zip { a: a_b, b: b_b }),
Zip { a: a_c, b: b_c },
)
}
fn size_hint(&self) -> (usize, Option<usize>) {
let (l_a, u_a) = self.a.size_hint();
let (l_b, u_b) = self.b.size_hint();
let l = if l_a < l_b {
l_a
} else {
l_b
};
let u = match (u_a, u_b) {
(Some(a), Some(b)) => {
if a < b {
Some(a)
} else {
Some(b)
}
}
(Some(x), None) | (None, Some(x)) => Some(x),
_ => None,
};
(l, u)
}
}
impl<A: ExactSizeSpliterator, B: ExactSizeSpliterator> ExactSizeSpliterator for Zip<A, B> {
fn size(&self) -> usize {
let (a, b) = (self.a.size(), self.b.size());
if a < b {
a
} else {
b
}
}
}
impl<A: IntoIterator, B: IntoIterator> IntoIterator for Hide<Zip<A, B>> {
type Item = (A::Item, B::Item);
type IntoIter = ::std::iter::Zip<A::IntoIter, B::IntoIter>;
fn into_iter(self) -> Self::IntoIter {
let z = self.0;
z.a.into_iter().zip(z.b.into_iter())
}
}
impl<A: Split, B: Split> Split for Hide<Zip<A, B>> {
fn should_split(&self, mul: f32) -> Option<usize> {
let z = &self.0;
match (z.a.should_split(mul * ZIP_MUL), z.a.should_split(mul * ZIP_MUL)) {
(Some(a), Some(b)) => {
Some(if a > b { b } else { a })
}
_ => None
}
}
fn split(self, idx: usize) -> (Self, Self) {
let z = self.0;
let (a1, a2) = z.a.split(idx);
let (b1, b2) = z.b.split(idx);
(
Hide(Zip { a: a1, b: b1 }),
Hide(Zip { a: a2, b: b2 }),
)
}
}