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: ?Sized, C: SplitProcess<X, Y, S> + ?Sized> Process<X, Y> for Split<&C, &mut S> {
19    fn process(&mut self, x: X) -> Y {
20        self.config.process(self.state, x)
21    }
22
23    fn block(&mut self, x: &[X], y: &mut [Y]) {
24        self.config.block(self.state, x, y)
25    }
26}
27
28impl<X: Copy, S: ?Sized, C: SplitInplace<X, S> + ?Sized> Inplace<X> for Split<&C, &mut S> {
29    fn inplace(&mut self, xy: &mut [X]) {
30        self.config.inplace(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    /// Obtain a borrowing Split
48    ///
49    /// Stateful `Process` is implemented on the borrowing Split
50    pub fn as_mut(&mut self) -> Split<&C, &mut S> {
51        Split {
52            config: &self.config,
53            state: &mut self.state,
54        }
55    }
56}
57
58/// Stateless/stateful marker
59///
60/// To be used in `Split<Unsplit<P>, ()>` and `Split<(), Unsplit<P>>`
61/// to mark processors requiring no state and no configuration respectively.
62#[derive(Debug, Copy, Clone, Default)]
63#[repr(transparent)]
64pub struct Unsplit<P>(pub P);
65
66impl<C> Split<Unsplit<C>, ()> {
67    /// Create a stateless processor
68    pub fn stateless(config: C) -> Self {
69        Self::new(Unsplit(config), ())
70    }
71}
72
73impl<S> Split<(), Unsplit<S>> {
74    /// Create a state-only processor
75    pub fn stateful(state: S) -> Self {
76        Self::new((), Unsplit(state))
77    }
78}
79
80/// Unzip two splits into one
81impl<C0, C1, S0, S1> core::ops::Mul<Split<C1, S1>> for Split<C0, S0> {
82    type Output = Split<(C0, C1), (S0, S1)>;
83
84    fn mul(self, rhs: Split<C1, S1>) -> Self::Output {
85        Split::from((self, rhs))
86    }
87}
88
89/// Unzip two splits into one parallel
90impl<C0, C1, S0, S1> core::ops::Add<Split<C1, S1>> for Split<C0, S0> {
91    type Output = Split<Parallel<(C0, C1)>, (S0, S1)>;
92
93    fn add(self, rhs: Split<C1, S1>) -> Self::Output {
94        Split::from((self, rhs)).parallel()
95    }
96}
97
98/// Unzip two splits
99impl<C0, C1, S0, S1> From<(Split<C0, S0>, Split<C1, S1>)> for Split<(C0, C1), (S0, S1)> {
100    fn from(value: (Split<C0, S0>, Split<C1, S1>)) -> Self {
101        Split::new(
102            (value.0.config, value.1.config),
103            (value.0.state, value.1.state),
104        )
105    }
106}
107
108/// Unzip multiple splits
109impl<C, S, const N: usize> From<[Split<C, S>; N]> for Split<[C; N], [S; N]> {
110    fn from(splits: [Split<C, S>; N]) -> Self {
111        // Not efficient or nice, but this is usually not a hot path
112        let mut splits = splits.map(|s| (Some(s.config), Some(s.state)));
113        Self::new(
114            from_fn(|i| splits[i].0.take().unwrap()),
115            from_fn(|i| splits[i].1.take().unwrap()),
116        )
117    }
118}
119
120impl<C, S> Split<C, S> {
121    /// Convert to a configuration-minor split
122    pub fn minor<U>(self) -> Split<Minor<C, U>, S> {
123        Split::new(Minor::new(self.config), self.state)
124    }
125
126    /// Convert to intermediate buffered processor-major
127    pub fn major<U>(self) -> Split<Major<C, U>, S> {
128        Split::new(Major::new(self.config), self.state)
129    }
130
131    /// Convert to parallel (MIMO)
132    pub fn parallel(self) -> Split<Parallel<C>, S> {
133        Split::new(Parallel(self.config), self.state)
134    }
135
136    /// Repeat by cloning configuration and current (!) state
137    pub fn repeat<const N: usize>(self) -> Split<[C; N], [S; N]>
138    where
139        C: Clone,
140        S: Clone,
141    {
142        Split::new(repeat(self.config), repeat(self.state))
143    }
144
145    /// Apply to multiple states by cloning the current (!) state
146    pub fn channels<const N: usize>(self) -> Split<Channels<C>, [S; N]>
147    where
148        S: Clone,
149    {
150        Split::new(Channels(self.config), repeat(self.state))
151    }
152
153    /// Convert to parallel transpose operation on blocks/inplace of `[[x]; N]` instead of `[[x; N]]`
154    pub fn transpose(self) -> Split<Transpose<C>, S> {
155        Split::new(Transpose(self.config), self.state)
156    }
157}
158
159impl<C, S, U> Split<Minor<C, U>, S> {
160    /// Strip minor
161    pub fn inter(self) -> Split<C, S> {
162        Split::new(self.config.inner, self.state)
163    }
164}
165
166impl<C, S> Split<Parallel<C>, S> {
167    /// Convert to serial
168    pub fn inter(self) -> Split<C, S> {
169        Split::new(self.config.0, self.state)
170    }
171}
172
173impl<C, S> Split<Transpose<C>, S> {
174    /// Convert to non-transposing
175    pub fn inter(self) -> Split<C, S> {
176        Split::new(self.config.0, self.state)
177    }
178}
179
180impl<C, S, B> Split<Major<C, B>, S> {
181    /// Remove major intermediate buffering
182    pub fn inter(self) -> Split<C, S> {
183        Split::new(self.config.inner, self.state)
184    }
185}
186
187impl<C0, C1, S0, S1> Split<(C0, C1), (S0, S1)> {
188    /// Zip up a split
189    pub fn zip(self) -> (Split<C0, S0>, Split<C1, S1>) {
190        (
191            Split::new(self.config.0, self.state.0),
192            Split::new(self.config.1, self.state.1),
193        )
194    }
195}
196
197impl<C, S, const N: usize> Split<[C; N], [S; N]> {
198    /// Zip up a split
199    pub fn zip(self) -> [Split<C, S>; N] {
200        let mut it = self.config.into_iter().zip(self.state);
201        from_fn(|_| {
202            let (c, s) = it.next().unwrap();
203            Split::new(c, s)
204        })
205    }
206}
207
208/// Stateless filters
209impl<'a, X: Copy, Y, P> SplitProcess<X, Y> for Unsplit<&'a P>
210where
211    &'a P: Process<X, Y>,
212{
213    fn process(&self, _state: &mut (), x: X) -> Y {
214        (&*self.0).process(x)
215    }
216
217    fn block(&self, _state: &mut (), x: &[X], y: &mut [Y]) {
218        (&*self.0).block(x, y)
219    }
220}
221
222impl<'a, X: Copy, P> SplitInplace<X> for Unsplit<&'a P>
223where
224    &'a P: Inplace<X>,
225{
226    fn inplace(&self, _state: &mut (), xy: &mut [X]) {
227        (&*self.0).inplace(xy)
228    }
229}
230
231/// Configuration-less filters
232impl<X: Copy, Y, P: Process<X, Y>> SplitProcess<X, Y, Unsplit<P>> for () {
233    fn process(&self, state: &mut Unsplit<P>, x: X) -> Y {
234        state.0.process(x)
235    }
236
237    fn block(&self, state: &mut Unsplit<P>, x: &[X], y: &mut [Y]) {
238        state.0.block(x, y)
239    }
240}
241
242impl<X: Copy, P: Inplace<X>> SplitInplace<X, Unsplit<P>> for () {
243    fn inplace(&self, state: &mut Unsplit<P>, xy: &mut [X]) {
244        state.0.inplace(xy)
245    }
246}