Created
November 25, 2021 13:28
-
-
Save typetetris/095e18bd16de31ec57a89c51c7c818e4 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pub trait Filter { | |
type Input: Copy; | |
type Output; | |
fn process(&mut self, sample: Self::Input) -> Self::Output; | |
} | |
#[derive(Copy, Clone)] | |
pub struct Nil<X>(pub X); | |
#[derive(Copy, Clone)] | |
pub struct Cons<X, Xs: NonEmpty>(pub X, pub Xs); | |
pub trait NonEmpty {} | |
impl<X> NonEmpty for Nil<X> {} | |
impl<X, Xs: NonEmpty> NonEmpty for Cons<X, Xs> {} | |
pub trait NonEmptyConcatSplit { | |
type Output: NonEmpty; | |
fn concat(self) -> Self::Output; | |
fn split(to_be_split: Self::Output) -> Self; | |
} | |
impl<X, L2: NonEmpty> NonEmptyConcatSplit for (Nil<X>, L2) { | |
type Output = Cons<X, L2>; | |
fn concat(self) -> Self::Output { | |
let (Nil(x), l2) = self; | |
Cons(x, l2) | |
} | |
fn split(Cons(x, l2): Self::Output) -> Self { | |
(Nil(x), l2) | |
} | |
} | |
impl<X, Xs, L2> NonEmptyConcatSplit for (Cons<X, Xs>, L2) | |
where | |
Xs: NonEmpty, | |
(Xs, L2): NonEmptyConcatSplit, | |
{ | |
type Output = Cons<X, <(Xs, L2) as NonEmptyConcatSplit>::Output>; | |
fn concat(self) -> Self::Output { | |
let (Cons(x, xs), l2) = self; | |
Cons(x, (xs, l2).concat()) | |
} | |
fn split(Cons(x, rest): Self::Output) -> Self { | |
let (xs, l2) = <(Xs, L2) as NonEmptyConcatSplit>::split(rest); | |
(Cons(x, xs), l2) | |
} | |
} | |
pub struct LiftedFilter<I, O, F>(F, std::marker::PhantomData<I>, std::marker::PhantomData<O>); | |
impl<I, O, F> LiftedFilter<I, O, F> | |
where | |
F: Filter<Input = I, Output = O>, | |
{ | |
pub fn new(filter: F) -> Self { | |
LiftedFilter( | |
filter, | |
std::marker::PhantomData {}, | |
std::marker::PhantomData {}, | |
) | |
} | |
} | |
impl<I, O, F> Filter for LiftedFilter<I, O, F> | |
where | |
I: Copy, | |
F: Filter<Input = I, Output = O>, | |
{ | |
type Input = Nil<I>; | |
type Output = Nil<O>; | |
fn process(&mut self, Nil(sample): Nil<I>) -> Nil<O> { | |
Nil(self.0.process(sample)) | |
} | |
} | |
pub struct FilterStack<I1, O1, F1, I2, O2, F2>( | |
pub F1, | |
pub F2, | |
std::marker::PhantomData<I1>, | |
std::marker::PhantomData<O1>, | |
std::marker::PhantomData<I2>, | |
std::marker::PhantomData<O2>, | |
); | |
impl<I1, I2, O1, O2, F1, F2> FilterStack<I1, O1, F1, I2, O2, F2> | |
where | |
F1: Filter<Input = I1, Output = O1>, | |
F2: Filter<Input = I2, Output = O2>, | |
{ | |
pub fn new(filter1: F1, filter2: F2) -> Self { | |
FilterStack( | |
filter1, | |
filter2, | |
std::marker::PhantomData {}, | |
std::marker::PhantomData {}, | |
std::marker::PhantomData {}, | |
std::marker::PhantomData {}, | |
) | |
} | |
} | |
impl<I1, I2, O1, O2, F1, F2> Filter for FilterStack<I1, O1, F1, I2, O2, F2> | |
where | |
I1: NonEmpty + Copy, | |
I2: NonEmpty + Copy, | |
(I1, I2): NonEmptyConcatSplit, | |
<(I1, I2) as NonEmptyConcatSplit>::Output: Copy, | |
O1: NonEmpty, | |
O2: NonEmpty, | |
(O1, O2): NonEmptyConcatSplit, | |
F1: Filter<Input = I1, Output = O1>, | |
F2: Filter<Input = I2, Output = O2>, | |
{ | |
type Input = <(I1, I2) as NonEmptyConcatSplit>::Output; | |
type Output = <(O1, O2) as NonEmptyConcatSplit>::Output; | |
fn process(&mut self, sample: Self::Input) -> Self::Output { | |
let (i1, i2) = <(I1, I2) as NonEmptyConcatSplit>::split(sample); | |
let (o1, o2) = (self.0.process(i1), self.1.process(i2)); | |
(o1, o2).concat() | |
} | |
} | |
pub struct Dup<I, X>( | |
pub std::marker::PhantomData<I>, | |
pub std::marker::PhantomData<X>, | |
); | |
impl<I, X> Default for Dup<I, X> { | |
fn default() -> Self { | |
Self::new() | |
} | |
} | |
impl<I, X> Dup<I, X> { | |
pub fn new() -> Self { | |
Dup(std::marker::PhantomData {}, std::marker::PhantomData {}) | |
} | |
} | |
impl<I> Filter for Dup<I, Nil<I>> | |
where | |
I: Copy, | |
{ | |
type Input = I; | |
type Output = Nil<I>; | |
fn process(&mut self, sample: I) -> Nil<I> { | |
Nil(sample) | |
} | |
} | |
impl<I, Is> Filter for Dup<I, Cons<I, Is>> | |
where | |
I: Copy, | |
Is: NonEmpty, | |
Dup<I, Is>: Filter<Input = I, Output = Is>, | |
{ | |
type Input = I; | |
type Output = Cons<I, Is>; | |
fn process(&mut self, sample: I) -> Cons<I, Is> { | |
let mut rest_f: Dup<I, Is> = Dup(std::marker::PhantomData {}, std::marker::PhantomData {}); | |
let rest = rest_f.process(sample); | |
Cons(sample, rest) | |
} | |
} | |
pub struct Attach<I1, O1, F1, O2, F2>( | |
F1, | |
F2, | |
std::marker::PhantomData<I1>, | |
std::marker::PhantomData<O1>, | |
std::marker::PhantomData<O2>, | |
); | |
impl<I1, O1, F1, O2, F2> Attach<I1, O1, F1, O2, F2> | |
where | |
I1: Copy, | |
O1: Copy, | |
F1: Filter<Input = I1, Output = O1>, | |
F2: Filter<Input = O1, Output = O2>, | |
{ | |
pub fn new(filter1: F1, filter2: F2) -> Self { | |
Attach( | |
filter1, | |
filter2, | |
std::marker::PhantomData {}, | |
std::marker::PhantomData {}, | |
std::marker::PhantomData {}, | |
) | |
} | |
} | |
impl<I1, O1, F1, O2, F2> Filter for Attach<I1, O1, F1, O2, F2> | |
where | |
I1: Copy, | |
O1: Copy, | |
F1: Filter<Input = I1, Output = O1>, | |
F2: Filter<Input = O1, Output = O2>, | |
{ | |
type Input = I1; | |
type Output = O2; | |
fn process(&mut self, sample: I1) -> O2 { | |
let first = self.0.process(sample); | |
self.1.process(first) | |
} | |
} | |
#[cfg(test)] | |
mod tests { | |
use super::*; | |
struct Silence; | |
impl Filter for Silence { | |
type Input = f64; | |
type Output = f64; | |
fn process(&mut self, _sample: f64) -> f64 { | |
0f64 | |
} | |
} | |
#[test] | |
fn dup() { | |
let stacked_silence = | |
FilterStack::new(LiftedFilter::new(Silence {}), LiftedFilter::new(Silence {})); | |
let dup: Dup<f64, Cons<f64,Nil<f64>>> = Dup::new(); | |
let _result = Attach::new(dup, stacked_silence); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment