autd3_driver/datagram/
boxed.rs

1use std::mem::MaybeUninit;
2
3use crate::{
4    datagram::Datagram,
5    error::AUTDDriverError,
6    firmware::operation::{BoxedOperation, OperationGenerator},
7};
8use autd3_core::{
9    datagram::{DatagramOption, Operation},
10    geometry::{Device, Geometry},
11};
12
13pub trait DOperationGenerator {
14    #[must_use]
15    fn dyn_generate(&mut self, device: &Device) -> (BoxedOperation, BoxedOperation);
16}
17
18#[cfg(feature = "lightweight")]
19type DynDOperationGenerator = Box<dyn DOperationGenerator + Send>;
20#[cfg(not(feature = "lightweight"))]
21type DynDOperationGenerator = Box<dyn DOperationGenerator>;
22
23pub struct DynOperationGenerator {
24    g: DynDOperationGenerator,
25}
26
27impl OperationGenerator for DynOperationGenerator {
28    type O1 = BoxedOperation;
29    type O2 = BoxedOperation;
30
31    fn generate(&mut self, device: &Device) -> (Self::O1, Self::O2) {
32        self.g.dyn_generate(device)
33    }
34}
35
36impl<G: OperationGenerator> DOperationGenerator for G
37where
38    G::O1: 'static,
39    G::O2: 'static,
40    AUTDDriverError: From<<G::O1 as Operation>::Error> + From<<G::O2 as Operation>::Error>,
41{
42    fn dyn_generate(&mut self, device: &Device) -> (BoxedOperation, BoxedOperation) {
43        let (o1, o2) = self.generate(device);
44        (BoxedOperation::new(o1), BoxedOperation::new(o2))
45    }
46}
47
48pub trait DDatagram: std::fmt::Debug {
49    fn dyn_operation_generator(
50        &mut self,
51        geometry: &Geometry,
52        parallel: bool,
53    ) -> Result<DynDOperationGenerator, AUTDDriverError>;
54    #[must_use]
55    fn dyn_option(&self) -> DatagramOption;
56    fn dyn_fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result;
57}
58
59impl<
60    E,
61    #[cfg(feature = "lightweight")] G: DOperationGenerator + Send + 'static,
62    #[cfg(not(feature = "lightweight"))] G: DOperationGenerator + 'static,
63    T: Datagram<G = G, Error = E>,
64> DDatagram for MaybeUninit<T>
65where
66    AUTDDriverError: From<E>,
67{
68    fn dyn_operation_generator(
69        &mut self,
70        geometry: &Geometry,
71        parallel: bool,
72    ) -> Result<DynDOperationGenerator, AUTDDriverError> {
73        let mut tmp = MaybeUninit::<T>::uninit();
74        std::mem::swap(&mut tmp, self);
75        let d = unsafe { tmp.assume_init() };
76        Ok(Box::new(d.operation_generator(geometry, parallel)?))
77    }
78
79    fn dyn_option(&self) -> DatagramOption {
80        unsafe { self.assume_init_ref() }.option()
81    }
82
83    fn dyn_fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
84        unsafe { self.assume_init_ref() }.fmt(f)
85    }
86}
87
88/// Boxed [`Datagram`].
89pub struct BoxedDatagram {
90    d: Box<dyn DDatagram>,
91}
92
93#[cfg(feature = "lightweight")]
94unsafe impl Send for BoxedDatagram {}
95#[cfg(feature = "lightweight")]
96unsafe impl Sync for BoxedDatagram {}
97
98impl std::fmt::Debug for BoxedDatagram {
99    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
100        self.d.dyn_fmt(f)
101    }
102}
103
104impl BoxedDatagram {
105    fn new<
106        E,
107        #[cfg(feature = "lightweight")] G: OperationGenerator + Send + 'static,
108        #[cfg(not(feature = "lightweight"))] G: OperationGenerator + 'static,
109        D: Datagram<G = G, Error = E> + 'static,
110    >(
111        d: D,
112    ) -> Self
113    where
114        AUTDDriverError: From<E>,
115        AUTDDriverError: From<<G::O1 as Operation>::Error> + From<<G::O2 as Operation>::Error>,
116    {
117        BoxedDatagram {
118            d: Box::new(MaybeUninit::new(d)),
119        }
120    }
121}
122
123impl Datagram for BoxedDatagram {
124    type G = DynOperationGenerator;
125    type Error = AUTDDriverError;
126
127    fn operation_generator(
128        self,
129        geometry: &Geometry,
130        parallel: bool,
131    ) -> Result<Self::G, Self::Error> {
132        let Self { mut d } = self;
133        Ok(DynOperationGenerator {
134            g: d.dyn_operation_generator(geometry, parallel)?,
135        })
136    }
137
138    fn option(&self) -> DatagramOption {
139        self.d.dyn_option()
140    }
141}
142
143/// Trait to convert [`Datagram`] to [`BoxedDatagram`].
144pub trait IntoBoxedDatagram {
145    /// Convert [`Datagram`] to [`BoxedDatagram`]
146    #[must_use]
147    fn into_boxed(self) -> BoxedDatagram;
148}
149
150impl<
151    E,
152    #[cfg(feature = "lightweight")] G: OperationGenerator + Send + 'static,
153    #[cfg(not(feature = "lightweight"))] G: OperationGenerator + 'static,
154    #[cfg(feature = "lightweight")] D: Datagram<Error = E, G = G> + Send + 'static,
155    #[cfg(not(feature = "lightweight"))] D: Datagram<Error = E, G = G> + 'static,
156> IntoBoxedDatagram for D
157where
158    AUTDDriverError: From<E>,
159    AUTDDriverError: From<<G::O1 as Operation>::Error> + From<<G::O2 as Operation>::Error>,
160{
161    fn into_boxed(self) -> BoxedDatagram {
162        BoxedDatagram::new(self)
163    }
164}
165
166#[cfg(test)]
167mod tests {
168
169    use super::*;
170
171    // GRCOV_EXCL_START
172    struct TestDatagram;
173    struct TestOperationGenerator;
174
175    impl OperationGenerator for TestOperationGenerator {
176        type O1 = autd3_core::datagram::NullOp;
177        type O2 = autd3_core::datagram::NullOp;
178
179        fn generate(&mut self, _device: &Device) -> (Self::O1, Self::O2) {
180            unimplemented!()
181        }
182    }
183
184    impl Datagram for TestDatagram {
185        type G = TestOperationGenerator;
186        type Error = AUTDDriverError;
187
188        fn operation_generator(
189            self,
190            _geometry: &Geometry,
191            _parallel: bool,
192        ) -> Result<Self::G, Self::Error> {
193            Ok(Self::G {})
194        }
195    }
196    // GRCOV_EXCL_STOP
197
198    impl std::fmt::Debug for TestDatagram {
199        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
200            write!(f, "test")
201        }
202    }
203
204    #[test]
205    fn boxed_fmt() {
206        let d = TestDatagram;
207        let bd = BoxedDatagram::new(d);
208        assert_eq!(format!("{:?}", bd), "test");
209    }
210}