pub trait Reductor<A>: Sized {
type State;
fn new(item: A) -> Self::State;
fn reduce(state: Self::State, item: A) -> Self::State;
fn into_result(state: Self::State) -> Self;
}
impl<R, A> Reductor<A> for Option<R>
where
R: Reductor<A>,
{
type State = Option<R::State>;
fn new(item: A) -> Self::State {
Some(R::new(item))
}
fn reduce(state: Self::State, item: A) -> Self::State {
Some(match state {
None => R::new(item),
Some(state) => R::reduce(state, item),
})
}
fn into_result(state: Self::State) -> Self {
state.map(R::into_result)
}
}
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Reductors<R>(pub R);
#[rustfmt::skip]
mod agg_impls {
use super::*;
macro_rules! impl_reductor_for_tuple {
($(#[$meta:meta])* $([$A:ident: $R:ident, $Idx:tt]),+$(,)?) => {
$(#[$meta])*
impl<$($A),+, $($R),+> Reductor<($($A),+)> for ($($R),+)
where
$($R: Reductor<$A>),+
{
type State = ($($R::State),+);
fn new(item: ($($A),+)) -> Self::State {
($($R::new(item.$Idx)),+)
}
fn reduce(state: Self::State, item: ($($A),+)) -> Self::State {
($($R::reduce(state.$Idx, item.$Idx)),+)
}
fn into_result(state: Self::State) -> Self {
($($R::into_result(state.$Idx)),+)
}
}
};
}
impl_reductor_for_tuple!(
[A1: R1, 0], [A2: R2, 1],
);
impl_reductor_for_tuple!([A1: R1, 0], [A2: R2, 1], [A3: R3, 2]);
impl_reductor_for_tuple!([A1: R1, 0], [A2: R2, 1], [A3: R3, 2], [A4: R4, 3]);
impl_reductor_for_tuple!([A1: R1, 0], [A2: R2, 1], [A3: R3, 2], [A4: R4, 3], [A5: R5, 4]);
macro_rules! impl_reductor_for_reductors {
($(#[$meta:meta])* $([$R:ident, $Idx:tt]),+$(,)?) => {
$(#[$meta])*
impl<A, $($R),+> Reductor<A> for Reductors<($($R),+)>
where
A: Clone,
$($R: Reductor<A>),+
{
type State = ($($R::State),+);
fn new(item: A) -> Self::State {
($($R::new(item.clone())),+)
}
fn reduce(state: Self::State, item: A) -> Self::State {
($($R::reduce(state.$Idx, item.clone())),+)
}
fn into_result(state: Self::State) -> Self {
Self(($($R::into_result(state.$Idx)),+))
}
}
};
}
impl_reductor_for_reductors!([R1, 0], [R2, 1]);
impl_reductor_for_reductors!([R1, 0], [R2, 1], [R3, 2]);
impl_reductor_for_reductors!([R1, 0], [R2, 1], [R3, 2], [R4, 3]);
impl_reductor_for_reductors!([R1, 0], [R2, 1], [R3, 2], [R4, 3], [R5, 4]);
}