autd3_driver/datagram/modulation/
boxed.rs

1use std::mem::MaybeUninit;
2
3use autd3_core::derive::*;
4use autd3_derive::Modulation;
5
6/// A dyn-compatible version of [`Modulation`].
7pub trait DModulation {
8    fn dyn_calc(&mut self) -> Result<Vec<u8>, ModulationError>;
9    fn dyn_fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result;
10}
11
12impl<
13    #[cfg(not(feature = "lightweight"))] T: Modulation,
14    #[cfg(feature = "lightweight")] T: Modulation + Send + Sync,
15> DModulation for MaybeUninit<T>
16{
17    fn dyn_calc(&mut self) -> Result<Vec<u8>, ModulationError> {
18        let mut tmp: MaybeUninit<T> = MaybeUninit::uninit();
19        std::mem::swap(&mut tmp, self);
20        // SAFETY: This function is called only once from `Modulation::calc`.
21        let g = unsafe { tmp.assume_init() };
22        g.calc()
23    }
24
25    fn dyn_fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
26        // SAFETY: This function is never called after `dyn_init`.
27        unsafe { self.assume_init_ref() }.fmt(f)
28    }
29}
30
31/// Boxed [`Modulation`].
32///
33/// This provides the ability to wrap any [`Modulation`] in a common type.
34#[derive(Modulation)]
35pub struct BoxedModulation {
36    m: Box<dyn DModulation>,
37    sampling_config: SamplingConfig,
38}
39
40impl BoxedModulation {
41    /// Creates a new [`BoxedModulation`].
42    pub fn new<
43        #[cfg(not(feature = "lightweight"))] M: Modulation + 'static,
44        #[cfg(feature = "lightweight")] M: Modulation + Send + Sync + 'static,
45    >(
46        m: M,
47    ) -> BoxedModulation {
48        let sampling_config = m.sampling_config();
49        BoxedModulation {
50            m: Box::new(MaybeUninit::new(m)),
51            sampling_config,
52        }
53    }
54}
55
56#[cfg(feature = "lightweight")]
57unsafe impl Send for BoxedModulation {}
58#[cfg(feature = "lightweight")]
59unsafe impl Sync for BoxedModulation {}
60
61impl std::fmt::Debug for BoxedModulation {
62    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
63        self.m.as_ref().dyn_fmt(f)
64    }
65}
66
67impl Modulation for BoxedModulation {
68    fn calc(self) -> Result<Vec<u8>, ModulationError> {
69        let Self { mut m, .. } = self;
70        m.dyn_calc()
71    }
72
73    fn sampling_config(&self) -> SamplingConfig {
74        self.sampling_config
75    }
76}
77
78/// Trait to convert [`Modulation`] to [`BoxedModulation`].
79pub trait IntoBoxedModulation {
80    /// Convert [`Modulation`] to [`BoxedModulation`]
81    #[must_use]
82    fn into_boxed(self) -> BoxedModulation;
83}
84
85impl<
86    #[cfg(not(feature = "lightweight"))] M: Modulation + 'static,
87    #[cfg(feature = "lightweight")] M: Modulation + Send + Sync + 'static,
88> IntoBoxedModulation for M
89{
90    fn into_boxed(self) -> BoxedModulation {
91        BoxedModulation::new(self)
92    }
93}
94
95#[cfg(test)]
96pub mod tests {
97    use super::*;
98    use crate::datagram::modulation::tests::TestModulation;
99
100    #[test]
101    fn boxed_modulation_unsafe() {
102        let m = TestModulation {
103            sampling_config: SamplingConfig::FREQ_4K,
104        };
105
106        let mb = m.clone().into_boxed();
107
108        assert_eq!(format!("{:?}", m), format!("{:?}", mb));
109        assert_eq!(SamplingConfig::FREQ_4K, mb.sampling_config());
110        assert_eq!(Ok(vec![0; 2]), mb.calc());
111    }
112}