use crate::{Fold, FoldContext, FoldOutcome};
pub struct SequentialFold<L, S1, S2, F1, F2, M>
where
F1: Fold<L, S1>,
F2: Fold<L, S2>,
M: Fn(&S1, &FoldContext) -> FoldContext,
{
first: F1,
second: F2,
context_mapper: M,
_phantom: std::marker::PhantomData<(L, S1, S2)>,
}
impl<L, S1, S2, F1, F2, M> SequentialFold<L, S1, S2, F1, F2, M>
where
F1: Fold<L, S1>,
F2: Fold<L, S2>,
M: Fn(&S1, &FoldContext) -> FoldContext,
{
pub fn new(first: F1, second: F2, context_mapper: M) -> Self {
Self {
first,
second,
context_mapper,
_phantom: std::marker::PhantomData,
}
}
pub fn execute<'a, I>(
&self,
entries: I,
context: &FoldContext,
) -> (FoldOutcome<S1>, FoldOutcome<S2>)
where
I: IntoIterator<Item = &'a L> + Clone,
L: 'a,
{
let result1 = self.first.derive(entries.clone(), context);
let context2 = (self.context_mapper)(&result1.state, context);
let result2 = self.second.derive(entries, &context2);
(result1, result2)
}
}
pub struct DualFold<L, S1, S2, F1, F2>
where
F1: Fold<L, S1>,
F2: Fold<L, S2>,
{
fold1: F1,
fold2: F2,
_phantom: std::marker::PhantomData<(L, S1, S2)>,
}
impl<L, S1, S2, F1, F2> DualFold<L, S1, S2, F1, F2>
where
F1: Fold<L, S1>,
F2: Fold<L, S2>,
{
pub fn new(fold1: F1, fold2: F2) -> Self {
Self {
fold1,
fold2,
_phantom: std::marker::PhantomData,
}
}
pub fn execute<'a, I>(
&self,
entries: I,
context: &FoldContext,
) -> (FoldOutcome<S1>, FoldOutcome<S2>)
where
I: IntoIterator<Item = &'a L> + Clone,
L: 'a,
{
let result1 = self.fold1.derive(entries.clone(), context);
let result2 = self.fold2.derive(entries, context);
(result1, result2)
}
}
pub struct FilterFold<L, S, F, P>
where
F: Fold<L, S>,
P: Fn(&L) -> bool,
{
inner: F,
predicate: P,
_phantom: std::marker::PhantomData<(L, S)>,
}
impl<L, S, F, P> FilterFold<L, S, F, P>
where
F: Fold<L, S>,
P: Fn(&L) -> bool,
{
pub fn new(inner: F, predicate: P) -> Self {
Self {
inner,
predicate,
_phantom: std::marker::PhantomData,
}
}
}
impl<L, S, F, P> Fold<L, S> for FilterFold<L, S, F, P>
where
L: Send + Sync,
S: Send + Sync,
F: Fold<L, S>,
P: Fn(&L) -> bool + Send + Sync,
{
fn init(&self, context: &FoldContext) -> S {
self.inner.init(context)
}
fn reduce(&self, state: S, entry: &L, context: &FoldContext) -> S {
if (self.predicate)(entry) {
self.inner.reduce(state, entry, context)
} else {
state
}
}
fn finalize(&self, state: S, context: &FoldContext) -> S {
self.inner.finalize(state, context)
}
}
pub struct MapFold<L1, L2, S, F, M>
where
F: Fold<L2, S>,
M: Fn(&L1) -> L2,
{
inner: F,
mapper: M,
_phantom: std::marker::PhantomData<(L1, L2, S)>,
}
impl<L1, L2, S, F, M> MapFold<L1, L2, S, F, M>
where
F: Fold<L2, S>,
M: Fn(&L1) -> L2,
{
pub fn new(inner: F, mapper: M) -> Self {
Self {
inner,
mapper,
_phantom: std::marker::PhantomData,
}
}
}
impl<L1, L2, S, F, M> Fold<L1, S> for MapFold<L1, L2, S, F, M>
where
L1: Send + Sync,
L2: Send + Sync,
S: Send + Sync,
F: Fold<L2, S>,
M: Fn(&L1) -> L2 + Send + Sync,
{
fn init(&self, context: &FoldContext) -> S {
self.inner.init(context)
}
fn reduce(&self, state: S, entry: &L1, context: &FoldContext) -> S {
let mapped = (self.mapper)(entry);
self.inner.reduce(state, &mapped, context)
}
fn finalize(&self, state: S, context: &FoldContext) -> S {
self.inner.finalize(state, context)
}
}
pub fn filter<L, S, F, P>(inner: F, predicate: P) -> FilterFold<L, S, F, P>
where
F: Fold<L, S>,
P: Fn(&L) -> bool,
{
FilterFold::new(inner, predicate)
}
pub fn map<L1, L2, S, F, M>(inner: F, mapper: M) -> MapFold<L1, L2, S, F, M>
where
F: Fold<L2, S>,
M: Fn(&L1) -> L2,
{
MapFold::new(inner, mapper)
}
#[cfg(test)]
#[path = "compose_tests.rs"]
mod tests;