Skip to main content

dsp_process/
split.rs

1use core::array::{from_fn, repeat};
2
3use crate::{
4    Channels, Inplace, Major, Minor, Parallel, Process, SplitInplace, SplitProcess, Transpose,
5};
6
7//////////// SPLIT ////////////
8
9/// A stateful processor with split state
10#[derive(Debug, Copy, Clone, Default)]
11pub struct Split<C, S> {
12    /// Processor configuration
13    pub config: C,
14    /// Processor state
15    pub state: S,
16}
17
18impl<X: Copy, Y, S, C: SplitProcess<X, Y, S>> Process<X, Y> for Split<C, S> {
19    fn process(&mut self, x: X) -> Y {
20        self.config.process(&mut self.state, x)
21    }
22
23    fn block(&mut self, x: &[X], y: &mut [Y]) {
24        self.config.block(&mut self.state, x, y)
25    }
26}
27
28impl<X: Copy, S, C: SplitInplace<X, S>> Inplace<X> for Split<C, S> {
29    fn inplace(&mut self, xy: &mut [X]) {
30        self.config.inplace(&mut self.state, xy);
31    }
32}
33
34impl<C, S> Split<C, S> {
35    /// Create a new Split
36    pub const fn new(config: C, state: S) -> Self {
37        Self { config, state }
38    }
39
40    /// Statically assert that this implements Process<X, Y>
41    pub const fn assert_process<X: Copy, Y>(&self)
42    where
43        Self: Process<X, Y>,
44    {
45    }
46}
47
48/// Stateless/stateful marker
49///
50/// To be used in `Split<Unsplit<P>, ()>` and `Split<(), Unsplit<P>>`
51/// to mark processors requiring no state and no configuration respectively.
52#[derive(Debug, Copy, Clone, Default)]
53#[repr(transparent)]
54pub struct Unsplit<P>(pub P);
55
56impl<C> Split<C, ()> {
57    /// Create a stateless processor
58    pub fn stateless(config: C) -> Self {
59        Self::new(config, ())
60    }
61}
62
63impl<S> Split<(), Unsplit<S>> {
64    /// Create a state-only processor
65    pub fn stateful(state: S) -> Self {
66        Self::new((), Unsplit(state))
67    }
68}
69
70/// Unzip two splits into one
71impl<C0, C1, S0, S1> core::ops::Mul<Split<C1, S1>> for Split<C0, S0> {
72    type Output = Split<(C0, C1), (S0, S1)>;
73
74    fn mul(self, rhs: Split<C1, S1>) -> Self::Output {
75        Split::from((self, rhs))
76    }
77}
78
79/// Unzip two splits into one parallel
80impl<C0, C1, S0, S1> core::ops::Add<Split<C1, S1>> for Split<C0, S0> {
81    type Output = Split<Parallel<(C0, C1)>, (S0, S1)>;
82
83    fn add(self, rhs: Split<C1, S1>) -> Self::Output {
84        Split::from((self, rhs)).parallel()
85    }
86}
87
88/// Unzip two splits
89impl<C0, C1, S0, S1> From<(Split<C0, S0>, Split<C1, S1>)> for Split<(C0, C1), (S0, S1)> {
90    fn from(value: (Split<C0, S0>, Split<C1, S1>)) -> Self {
91        Split::new(
92            (value.0.config, value.1.config),
93            (value.0.state, value.1.state),
94        )
95    }
96}
97
98/// Unzip multiple splits
99impl<C, S, const N: usize> From<[Split<C, S>; N]> for Split<[C; N], [S; N]> {
100    fn from(splits: [Split<C, S>; N]) -> Self {
101        // Not efficient or nice, but this is usually not a hot path
102        let mut splits = splits.map(|s| (Some(s.config), Some(s.state)));
103        Self::new(
104            from_fn(|i| splits[i].0.take().unwrap()),
105            from_fn(|i| splits[i].1.take().unwrap()),
106        )
107    }
108}
109
110impl<C, S> Split<C, S> {
111    /// Convert to a configuration-minor split
112    pub fn minor<U>(self) -> Split<Minor<C, U>, S> {
113        Split::new(Minor::new(self.config), self.state)
114    }
115
116    /// Convert to intermediate buffered processor-major
117    pub fn major<U>(self) -> Split<Major<C, U>, S> {
118        Split::new(Major::new(self.config), self.state)
119    }
120
121    /// Convert to parallel (MIMO)
122    pub fn parallel(self) -> Split<Parallel<C>, S> {
123        Split::new(Parallel(self.config), self.state)
124    }
125
126    /// Repeat by cloning configuration and current (!) state
127    pub fn repeat<const N: usize>(self) -> Split<[C; N], [S; N]>
128    where
129        C: Clone,
130        S: Clone,
131    {
132        Split::new(repeat(self.config), repeat(self.state))
133    }
134
135    /// Apply to multiple states by cloning the current (!) state
136    pub fn channels<const N: usize>(self) -> Split<Channels<C>, [S; N]>
137    where
138        S: Clone,
139    {
140        Split::new(Channels(self.config), repeat(self.state))
141    }
142
143    /// Convert to parallel transpose operation on blocks/inplace of `[[x]; N]` instead of `[[x; N]]`
144    pub fn transpose(self) -> Split<Transpose<C>, S> {
145        Split::new(Transpose(self.config), self.state)
146    }
147}
148
149impl<C, S, U> Split<Minor<C, U>, S> {
150    /// Strip minor
151    pub fn inter(self) -> Split<C, S> {
152        Split::new(self.config.inner, self.state)
153    }
154}
155
156impl<C, S> Split<Parallel<C>, S> {
157    /// Convert to serial
158    pub fn inter(self) -> Split<C, S> {
159        Split::new(self.config.0, self.state)
160    }
161}
162
163impl<C, S> Split<Transpose<C>, S> {
164    /// Convert to non-transposing
165    pub fn inter(self) -> Split<C, S> {
166        Split::new(self.config.0, self.state)
167    }
168}
169
170impl<C, S, B> Split<Major<C, B>, S> {
171    /// Remove major intermediate buffering
172    pub fn inter(self) -> Split<C, S> {
173        Split::new(self.config.inner, self.state)
174    }
175}
176
177impl<C0, C1, S0, S1> Split<(C0, C1), (S0, S1)> {
178    /// Zip up a split
179    pub fn zip(self) -> (Split<C0, S0>, Split<C1, S1>) {
180        (
181            Split::new(self.config.0, self.state.0),
182            Split::new(self.config.1, self.state.1),
183        )
184    }
185}
186
187impl<C, S, const N: usize> Split<[C; N], [S; N]> {
188    /// Zip up a split
189    pub fn zip(self) -> [Split<C, S>; N] {
190        let mut it = self.config.into_iter().zip(self.state);
191        from_fn(|_| {
192            let (c, s) = it.next().unwrap();
193            Split::new(c, s)
194        })
195    }
196}
197
198/// Configuration-less filters
199impl<X: Copy, Y, P: Process<X, Y>> SplitProcess<X, Y, Unsplit<P>> for () {
200    fn process(&self, state: &mut Unsplit<P>, x: X) -> Y {
201        state.0.process(x)
202    }
203
204    fn block(&self, state: &mut Unsplit<P>, x: &[X], y: &mut [Y]) {
205        state.0.block(x, y)
206    }
207}
208
209impl<X: Copy, P: Inplace<X>> SplitInplace<X, Unsplit<P>> for () {
210    fn inplace(&self, state: &mut Unsplit<P>, xy: &mut [X]) {
211        state.0.inplace(xy)
212    }
213}