use crate::step::Step;
use std::marker::PhantomData;
pub trait Transducer<In, Out>: Sized {
fn apply<Acc, R>(&self, reducer: R) -> Box<dyn Fn(Acc, In) -> Step<Acc>>
where
R: Fn(Acc, Out) -> Step<Acc> + 'static,
Acc: 'static,
In: 'static,
Out: 'static;
fn compose<Out2, T>(self, other: T) -> Compose<Self, T, In, Out, Out2>
where
T: Transducer<Out, Out2>,
Self: 'static,
Out: 'static,
Out2: 'static,
T: 'static,
{
Compose {
first: self,
second: other,
_phantom: PhantomData,
}
}
}
pub struct Identity<T> {
_phantom: PhantomData<T>,
}
impl<T> Identity<T> {
pub fn new() -> Self {
Identity {
_phantom: PhantomData,
}
}
}
impl<T> Default for Identity<T> {
fn default() -> Self {
Self::new()
}
}
impl<T: 'static> Transducer<T, T> for Identity<T> {
#[inline(always)]
fn apply<Acc, R>(&self, reducer: R) -> Box<dyn Fn(Acc, T) -> Step<Acc>>
where
R: Fn(Acc, T) -> Step<Acc> + 'static,
Acc: 'static,
T: 'static,
{
Box::new(reducer)
}
}
pub struct Compose<T1, T2, In, Mid, Out> {
first: T1,
second: T2,
_phantom: PhantomData<(In, Mid, Out)>,
}
impl<T1, T2, In, Mid, Out> Transducer<In, Out> for Compose<T1, T2, In, Mid, Out>
where
T1: Transducer<In, Mid>,
T2: Transducer<Mid, Out>,
In: 'static,
Mid: 'static,
Out: 'static,
{
#[inline(always)]
fn apply<Acc, R>(&self, reducer: R) -> Box<dyn Fn(Acc, In) -> Step<Acc>>
where
R: Fn(Acc, Out) -> Step<Acc> + 'static,
Acc: 'static,
{
let r2 = self.second.apply(reducer);
self.first.apply(r2)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::step::cont;
#[test]
fn test_identity() {
let id = Identity::<i32>::new();
let reducer = |acc: Vec<i32>, x: i32| {
let mut v = acc;
v.push(x);
cont(v)
};
let transformed = id.apply(reducer);
let result = transformed(vec![], 42);
assert_eq!(result.unwrap(), vec![42]);
}
#[test]
fn test_identity_laws() {
let id = Identity::<i32>::new();
let reducer = |acc: i32, x: i32| cont(acc + x);
let transformed = id.apply(reducer);
assert_eq!(transformed(0, 5).unwrap(), 5);
assert_eq!(transformed(10, 5).unwrap(), 15);
}
}