autd3_driver/firmware/operation/implement/
boxed.rs

1use std::mem::MaybeUninit;
2
3use crate::{
4    error::AUTDDriverError,
5    firmware::operation::{Operation, OperationGenerator},
6};
7
8use autd3_core::{
9    datagram::{DatagramOption, DeviceMask},
10    derive::Datagram,
11    environment::Environment,
12    geometry::{Device, Geometry},
13};
14
15pub trait DOperation: Send {
16    #[must_use]
17    fn required_size(&self, device: &Device) -> usize;
18    fn pack(&mut self, device: &Device, tx: &mut [u8]) -> Result<usize, AUTDDriverError>;
19    #[must_use]
20    fn is_done(&self) -> bool;
21}
22
23#[doc(hidden)]
24pub struct BoxedOperation {
25    pub(crate) inner: Box<dyn DOperation>,
26}
27
28#[doc(hidden)]
29pub trait DOperationGenerator {
30    #[must_use]
31    fn dyn_generate(&mut self, device: &Device) -> Option<(BoxedOperation, BoxedOperation)>;
32}
33
34#[doc(hidden)]
35pub struct DynOperationGenerator {
36    pub(crate) g: Box<dyn DOperationGenerator>,
37}
38
39pub trait DDatagram {
40    fn dyn_operation_generator(
41        &mut self,
42        geometry: &Geometry,
43        env: &Environment,
44        filter: &DeviceMask,
45    ) -> Result<Box<dyn DOperationGenerator>, AUTDDriverError>;
46    #[must_use]
47    fn dyn_option(&self) -> DatagramOption;
48}
49
50impl<'a, T: Datagram<'a>> DDatagram for MaybeUninit<T>
51where
52    T::G: DOperationGenerator + 'static,
53    AUTDDriverError: From<T::Error>,
54{
55    #[allow(clippy::missing_transmute_annotations)]
56    fn dyn_operation_generator(
57        &mut self,
58        geometry: &Geometry,
59        env: &Environment,
60        filter: &DeviceMask,
61    ) -> Result<Box<dyn DOperationGenerator>, AUTDDriverError> {
62        let mut tmp = MaybeUninit::<T>::uninit();
63        std::mem::swap(&mut tmp, self);
64        let d = unsafe { tmp.assume_init() };
65        Ok(Box::new(d.operation_generator(
66            unsafe { std::mem::transmute(geometry) },
67            env,
68            filter,
69        )?))
70    }
71
72    fn dyn_option(&self) -> DatagramOption {
73        unsafe { self.assume_init_ref() }.option()
74    }
75}
76
77/// Boxed [`Datagram`].
78pub struct BoxedDatagram {
79    d: Box<dyn DDatagram>,
80}
81
82impl BoxedDatagram {
83    /// Creates a new [`BoxedDatagram`].
84    pub fn new<
85        'a,
86        E,
87        G: DOperationGenerator + 'static,
88        D: Datagram<'a, G = G, Error = E> + 'static,
89    >(
90        d: D,
91    ) -> Self
92    where
93        AUTDDriverError: From<E>,
94    {
95        BoxedDatagram {
96            d: Box::new(MaybeUninit::new(d)),
97        }
98    }
99}
100
101impl<'a> Datagram<'a> for BoxedDatagram {
102    type G = DynOperationGenerator;
103    type Error = AUTDDriverError;
104
105    fn operation_generator(
106        self,
107        geometry: &'a Geometry,
108        env: &Environment,
109        filter: &DeviceMask,
110    ) -> Result<Self::G, Self::Error> {
111        let Self { mut d } = self;
112        Ok(DynOperationGenerator {
113            g: d.dyn_operation_generator(geometry, env, filter)?,
114        })
115    }
116
117    fn option(&self) -> DatagramOption {
118        self.d.dyn_option()
119    }
120}
121
122impl<'a, O: Operation<'a>> DOperation for O
123where
124    AUTDDriverError: From<O::Error>,
125{
126    #[allow(clippy::missing_transmute_annotations)]
127    fn required_size(&self, device: &Device) -> usize {
128        O::required_size(self, unsafe { std::mem::transmute(device) })
129    }
130
131    #[allow(clippy::missing_transmute_annotations)]
132    fn pack(&mut self, device: &Device, tx: &mut [u8]) -> Result<usize, AUTDDriverError> {
133        Ok(O::pack(self, unsafe { std::mem::transmute(device) }, tx)?)
134    }
135
136    fn is_done(&self) -> bool {
137        O::is_done(self)
138    }
139}
140
141impl<'a> Operation<'a> for BoxedOperation {
142    type Error = AUTDDriverError;
143
144    fn required_size(&self, device: &'a Device) -> usize {
145        self.inner.required_size(device)
146    }
147
148    fn pack(&mut self, device: &'a Device, tx: &mut [u8]) -> Result<usize, Self::Error> {
149        self.inner.pack(device, tx)
150    }
151
152    fn is_done(&self) -> bool {
153        self.inner.is_done()
154    }
155}
156
157impl<'a> OperationGenerator<'a> for DynOperationGenerator {
158    type O1 = BoxedOperation;
159    type O2 = BoxedOperation;
160
161    fn generate(&mut self, device: &'a Device) -> Option<(Self::O1, Self::O2)> {
162        self.g.dyn_generate(device)
163    }
164}
165
166impl<'a, G: OperationGenerator<'a>> DOperationGenerator for G
167where
168    G::O1: 'static,
169    G::O2: 'static,
170    AUTDDriverError: From<<G::O1 as Operation<'a>>::Error> + From<<G::O2 as Operation<'a>>::Error>,
171{
172    #[allow(clippy::missing_transmute_annotations)]
173    fn dyn_generate(&mut self, device: &Device) -> Option<(BoxedOperation, BoxedOperation)> {
174        self.generate(unsafe { std::mem::transmute(device) })
175            .map(move |(o1, o2)| {
176                (
177                    BoxedOperation {
178                        inner: Box::new(o1),
179                    },
180                    BoxedOperation {
181                        inner: Box::new(o2),
182                    },
183                )
184            })
185    }
186}
187
188#[cfg(test)]
189pub mod tests {
190    use super::*;
191
192    use rand::Rng;
193
194    use autd3_core::geometry::{Point3, Transducer, UnitQuaternion};
195
196    #[derive(Clone, Copy)]
197    pub struct TestOp {
198        pub req_size: usize,
199        pub pack_size: usize,
200        pub done: bool,
201    }
202
203    impl Operation<'_> for TestOp {
204        type Error = AUTDDriverError;
205
206        fn required_size(&self, _device: &Device) -> usize {
207            self.req_size
208        }
209
210        fn pack(&mut self, _device: &Device, _tx: &mut [u8]) -> Result<usize, Self::Error> {
211            Ok(self.pack_size)
212        }
213
214        fn is_done(&self) -> bool {
215            self.done
216        }
217    }
218
219    #[test]
220    fn op() {
221        let mut rng = rand::rng();
222
223        let mut op = TestOp {
224            req_size: rng.random::<u32>() as usize,
225            pack_size: rng.random::<u32>() as usize,
226            done: rng.random(),
227        };
228
229        let device = Device::new(
230            UnitQuaternion::identity(),
231            vec![Transducer::new(Point3::origin())],
232        );
233
234        let mut boxed_op = BoxedOperation {
235            inner: Box::new(op),
236        };
237        {
238            assert_eq!(
239                Operation::required_size(&op, &device),
240                Operation::required_size(&boxed_op, &device)
241            );
242            assert_eq!(
243                Operation::pack(&mut op, &device, &mut []),
244                Operation::pack(&mut boxed_op, &device, &mut [])
245            );
246            assert_eq!(Operation::is_done(&op), Operation::is_done(&boxed_op));
247        }
248    }
249}