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) -> Option<(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) -> Option<(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) -> Option<(BoxedOperation, BoxedOperation)> {
43        self.generate(device)
44            .map(|(o1, o2)| (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: &mut Geometry,
52    ) -> Result<DynDOperationGenerator, AUTDDriverError>;
53    #[must_use]
54    fn dyn_option(&self) -> DatagramOption;
55    fn dyn_fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result;
56}
57
58impl<
59    E,
60    #[cfg(feature = "lightweight")] G: DOperationGenerator + Send + 'static,
61    #[cfg(not(feature = "lightweight"))] G: DOperationGenerator + 'static,
62    T: Datagram<G = G, Error = E>,
63> DDatagram for MaybeUninit<T>
64where
65    AUTDDriverError: From<E>,
66{
67    fn dyn_operation_generator(
68        &mut self,
69        geometry: &mut Geometry,
70    ) -> Result<DynDOperationGenerator, AUTDDriverError> {
71        let mut tmp = MaybeUninit::<T>::uninit();
72        std::mem::swap(&mut tmp, self);
73        let d = unsafe { tmp.assume_init() };
74        Ok(Box::new(d.operation_generator(geometry)?))
75    }
76
77    fn dyn_option(&self) -> DatagramOption {
78        unsafe { self.assume_init_ref() }.option()
79    }
80
81    fn dyn_fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
82        unsafe { self.assume_init_ref() }.fmt(f)
83    }
84}
85
86/// Boxed [`Datagram`].
87pub struct BoxedDatagram {
88    d: Box<dyn DDatagram>,
89}
90
91#[cfg(feature = "lightweight")]
92unsafe impl Send for BoxedDatagram {}
93#[cfg(feature = "lightweight")]
94unsafe impl Sync for BoxedDatagram {}
95
96impl std::fmt::Debug for BoxedDatagram {
97    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
98        self.d.dyn_fmt(f)
99    }
100}
101
102impl BoxedDatagram {
103    /// Creates a new [`BoxedDatagram`].
104    pub fn new<
105        E,
106        #[cfg(feature = "lightweight")] G: OperationGenerator + Send + 'static,
107        #[cfg(not(feature = "lightweight"))] G: OperationGenerator + 'static,
108        D: Datagram<G = G, Error = E> + 'static,
109    >(
110        d: D,
111    ) -> Self
112    where
113        AUTDDriverError: From<E>,
114        AUTDDriverError: From<<G::O1 as Operation>::Error> + From<<G::O2 as Operation>::Error>,
115    {
116        BoxedDatagram {
117            d: Box::new(MaybeUninit::new(d)),
118        }
119    }
120}
121
122impl Datagram for BoxedDatagram {
123    type G = DynOperationGenerator;
124    type Error = AUTDDriverError;
125
126    fn operation_generator(self, geometry: &mut Geometry) -> Result<Self::G, Self::Error> {
127        let Self { mut d } = self;
128        Ok(DynOperationGenerator {
129            g: d.dyn_operation_generator(geometry)?,
130        })
131    }
132
133    fn option(&self) -> DatagramOption {
134        self.d.dyn_option()
135    }
136}
137
138/// Trait to convert [`Datagram`] to [`BoxedDatagram`].
139pub trait IntoBoxedDatagram {
140    /// Convert [`Datagram`] to [`BoxedDatagram`]
141    #[must_use]
142    fn into_boxed(self) -> BoxedDatagram;
143}
144
145impl<
146    E,
147    #[cfg(feature = "lightweight")] G: OperationGenerator + Send + 'static,
148    #[cfg(not(feature = "lightweight"))] G: OperationGenerator + 'static,
149    #[cfg(feature = "lightweight")] D: Datagram<Error = E, G = G> + Send + 'static,
150    #[cfg(not(feature = "lightweight"))] D: Datagram<Error = E, G = G> + 'static,
151> IntoBoxedDatagram for D
152where
153    AUTDDriverError: From<E>,
154    AUTDDriverError: From<<G::O1 as Operation>::Error> + From<<G::O2 as Operation>::Error>,
155{
156    fn into_boxed(self) -> BoxedDatagram {
157        BoxedDatagram::new(self)
158    }
159}
160
161#[cfg(test)]
162mod tests {
163    use crate::datagram::tests::create_geometry;
164
165    use super::*;
166
167    #[derive(Clone, Copy)]
168    struct TestDatagram {
169        pub option: DatagramOption,
170    }
171
172    struct TestOperationGenerator;
173
174    impl OperationGenerator for TestOperationGenerator {
175        type O1 = crate::firmware::operation::boxed::tests::TestOp;
176        type O2 = crate::firmware::operation::boxed::tests::TestOp;
177
178        fn generate(&mut self, _device: &Device) -> Option<(Self::O1, Self::O2)> {
179            Some((
180                Self::O1 {
181                    req_size: 1,
182                    pack_size: 2,
183                    done: false,
184                },
185                Self::O2 {
186                    req_size: 3,
187                    pack_size: 4,
188                    done: true,
189                },
190            ))
191        }
192    }
193
194    impl Datagram for TestDatagram {
195        type G = TestOperationGenerator;
196        type Error = AUTDDriverError;
197
198        fn operation_generator(self, _geometry: &mut Geometry) -> Result<Self::G, Self::Error> {
199            Ok(Self::G {})
200        }
201
202        fn option(&self) -> DatagramOption {
203            self.option
204        }
205    }
206
207    impl std::fmt::Debug for TestDatagram {
208        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
209            write!(f, "test")
210        }
211    }
212
213    #[test]
214    fn boxed_datagram() -> anyhow::Result<()> {
215        let mut geometry = create_geometry(1, 1);
216
217        let d = TestDatagram {
218            option: Default::default(),
219        };
220        let bd = d.into_boxed();
221
222        assert_eq!(d.option(), bd.option());
223
224        let mut g = Datagram::operation_generator(bd, &mut geometry)?;
225        let (mut op1, mut op2) = g.generate(&geometry[0]).unwrap();
226        assert_eq!(1, op1.required_size(&geometry[0]));
227        assert_eq!(2, op1.pack(&geometry[0], &mut [])?);
228        assert!(!op1.is_done());
229        assert_eq!(3, op2.required_size(&geometry[0]));
230        assert_eq!(4, op2.pack(&geometry[0], &mut [])?);
231        assert!(op2.is_done());
232
233        Ok(())
234    }
235
236    #[test]
237    fn boxed_fmt() {
238        let d = TestDatagram {
239            option: Default::default(),
240        };
241        let bd = BoxedDatagram::new(d);
242        assert_eq!(format!("{:?}", bd), "test");
243    }
244}