autd3_driver/firmware/driver/operation/
boxed.rs

1use std::mem::MaybeUninit;
2
3use crate::{
4    error::AUTDDriverError,
5    firmware::driver::{Operation, Version},
6};
7
8use autd3_core::{
9    datagram::{DatagramOption, DeviceFilter},
10    derive::{Datagram, FirmwareLimits},
11    environment::Environment,
12    geometry::{Device, Geometry},
13};
14
15pub trait DOperation: Send + Sync {
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(
32        &mut self,
33        device: &Device,
34        version: Version,
35    ) -> Option<(BoxedOperation, BoxedOperation)>;
36}
37
38pub struct DynOperationGenerator {
39    pub(crate) g: Box<dyn DOperationGenerator>,
40}
41
42pub trait DDatagram: std::fmt::Debug {
43    fn dyn_operation_generator(
44        &mut self,
45        geometry: &Geometry,
46        env: &Environment,
47        filter: &DeviceFilter,
48        limits: &FirmwareLimits,
49    ) -> Result<Box<dyn DOperationGenerator>, AUTDDriverError>;
50    #[must_use]
51    fn dyn_option(&self) -> DatagramOption;
52    fn dyn_fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result;
53}
54
55impl<E, G: DOperationGenerator + 'static, T: Datagram<G = G, Error = E>> DDatagram
56    for MaybeUninit<T>
57where
58    AUTDDriverError: From<E>,
59{
60    fn dyn_operation_generator(
61        &mut self,
62        geometry: &Geometry,
63        env: &Environment,
64        filter: &DeviceFilter,
65        limits: &FirmwareLimits,
66    ) -> Result<Box<dyn DOperationGenerator>, AUTDDriverError> {
67        let mut tmp = MaybeUninit::<T>::uninit();
68        std::mem::swap(&mut tmp, self);
69        let d = unsafe { tmp.assume_init() };
70        Ok(Box::new(
71            d.operation_generator(geometry, env, filter, limits)?,
72        ))
73    }
74
75    fn dyn_option(&self) -> DatagramOption {
76        unsafe { self.assume_init_ref() }.option()
77    }
78
79    fn dyn_fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
80        unsafe { self.assume_init_ref() }.fmt(f)
81    }
82}
83
84/// Boxed [`Datagram`].
85pub struct BoxedDatagram {
86    d: Box<dyn DDatagram>,
87}
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    /// Creates a new [`BoxedDatagram`].
97    pub fn new<E, G: DOperationGenerator + 'static, D: Datagram<G = G, Error = E> + 'static>(
98        d: D,
99    ) -> Self
100    where
101        AUTDDriverError: From<E>,
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        env: &Environment,
117        filter: &DeviceFilter,
118        limits: &FirmwareLimits,
119    ) -> Result<Self::G, Self::Error> {
120        let Self { mut d } = self;
121        Ok(DynOperationGenerator {
122            g: d.dyn_operation_generator(geometry, env, filter, limits)?,
123        })
124    }
125
126    fn option(&self) -> DatagramOption {
127        self.d.dyn_option()
128    }
129}
130
131impl<E, O: Operation<Error = E>> DOperation for O
132where
133    AUTDDriverError: From<E>,
134{
135    fn required_size(&self, device: &Device) -> usize {
136        O::required_size(self, device)
137    }
138
139    fn pack(&mut self, device: &Device, tx: &mut [u8]) -> Result<usize, AUTDDriverError> {
140        Ok(O::pack(self, device, tx)?)
141    }
142
143    fn is_done(&self) -> bool {
144        O::is_done(self)
145    }
146}
147
148impl Operation for BoxedOperation {
149    type Error = AUTDDriverError;
150
151    fn required_size(&self, device: &Device) -> usize {
152        self.inner.required_size(device)
153    }
154
155    fn pack(&mut self, device: &Device, tx: &mut [u8]) -> Result<usize, Self::Error> {
156        self.inner.pack(device, tx)
157    }
158
159    fn is_done(&self) -> bool {
160        self.inner.is_done()
161    }
162}
163
164#[cfg(test)]
165pub mod tests {
166    use super::*;
167
168    use rand::Rng;
169
170    use autd3_core::geometry::{Point3, Transducer, UnitQuaternion};
171
172    #[derive(Clone, Copy)]
173    pub struct TestOp {
174        pub req_size: usize,
175        pub pack_size: usize,
176        pub done: bool,
177    }
178
179    impl Operation for TestOp {
180        type Error = AUTDDriverError;
181
182        fn required_size(&self, _device: &Device) -> usize {
183            self.req_size
184        }
185
186        fn pack(&mut self, _device: &Device, _tx: &mut [u8]) -> Result<usize, Self::Error> {
187            Ok(self.pack_size)
188        }
189
190        fn is_done(&self) -> bool {
191            self.done
192        }
193    }
194
195    #[test]
196    fn test_boxed_operation() {
197        let mut rng = rand::rng();
198
199        let mut op = TestOp {
200            req_size: rng.random::<u32>() as usize,
201            pack_size: rng.random::<u32>() as usize,
202            done: rng.random(),
203        };
204        let mut boxed_op = BoxedOperation {
205            inner: Box::new(op),
206        };
207
208        let device = Device::new(
209            UnitQuaternion::identity(),
210            vec![Transducer::new(Point3::origin())],
211        );
212
213        assert_eq!(
214            Operation::required_size(&op, &device),
215            Operation::required_size(&boxed_op, &device)
216        );
217        assert_eq!(
218            Operation::pack(&mut op, &device, &mut []),
219            Operation::pack(&mut boxed_op, &device, &mut [])
220        );
221        assert_eq!(Operation::is_done(&op), Operation::is_done(&boxed_op));
222    }
223}