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