autd3_driver/datagram/modulation/
boxed.rs

1use std::mem::MaybeUninit;
2
3use autd3_core::derive::*;
4
5/// A dyn-compatible version of [`Modulation`].
6pub trait DModulation {
7    fn dyn_calc(&mut self) -> Result<Vec<u8>, ModulationError>;
8}
9
10impl<T: Modulation> DModulation for MaybeUninit<T> {
11    fn dyn_calc(&mut self) -> Result<Vec<u8>, ModulationError> {
12        let mut tmp: MaybeUninit<T> = MaybeUninit::uninit();
13        std::mem::swap(&mut tmp, self);
14        // SAFETY: This function is called only once from `BoxedModulation::calc`.
15        let g = unsafe { tmp.assume_init() };
16        g.calc()
17    }
18}
19
20/// Boxed [`Modulation`].
21///
22/// This provides the ability to wrap any [`Modulation`] in a common type.
23#[derive(Modulation)]
24pub struct BoxedModulation {
25    m: Box<dyn DModulation>,
26    sampling_config: SamplingConfig,
27}
28
29impl BoxedModulation {
30    /// Creates a new [`BoxedModulation`].
31    pub fn new<M: Modulation + 'static>(m: M) -> BoxedModulation {
32        let sampling_config = m.sampling_config();
33        BoxedModulation {
34            m: Box::new(MaybeUninit::new(m)),
35            sampling_config,
36        }
37    }
38}
39
40impl Modulation for BoxedModulation {
41    fn calc(self) -> Result<Vec<u8>, ModulationError> {
42        let Self { mut m, .. } = self;
43        m.dyn_calc()
44    }
45
46    fn sampling_config(&self) -> SamplingConfig {
47        self.sampling_config
48    }
49}
50
51#[cfg(test)]
52pub mod tests {
53    use super::*;
54    use crate::datagram::modulation::tests::TestModulation;
55
56    #[test]
57    fn new() {
58        let m = TestModulation {
59            sampling_config: SamplingConfig::FREQ_4K,
60        };
61
62        let mb = BoxedModulation::new(m.clone());
63
64        assert_eq!(SamplingConfig::FREQ_4K, mb.sampling_config());
65        assert_eq!(Ok(vec![0; 2]), mb.calc());
66    }
67}