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    geometry::{Device, Geometry},
12};
13
14pub trait DOperation: Send + Sync {
15    #[must_use]
16    fn required_size(&self, device: &Device) -> usize;
17    fn pack(&mut self, device: &Device, tx: &mut [u8]) -> Result<usize, AUTDDriverError>;
18    #[must_use]
19    fn is_done(&self) -> bool;
20}
21
22#[doc(hidden)]
23pub struct BoxedOperation {
24    pub(crate) inner: Box<dyn DOperation>,
25}
26
27#[doc(hidden)]
28pub trait DOperationGenerator {
29    #[must_use]
30    fn dyn_generate(
31        &mut self,
32        device: &Device,
33        version: Version,
34    ) -> Option<(BoxedOperation, BoxedOperation)>;
35}
36
37pub struct DynOperationGenerator {
38    pub(crate) g: Box<dyn DOperationGenerator>,
39}
40
41pub trait DDatagram: std::fmt::Debug {
42    fn dyn_operation_generator(
43        &mut self,
44        geometry: &Geometry,
45        filter: &DeviceFilter,
46        limits: &FirmwareLimits,
47    ) -> Result<Box<dyn DOperationGenerator>, AUTDDriverError>;
48    #[must_use]
49    fn dyn_option(&self) -> DatagramOption;
50    fn dyn_fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result;
51}
52
53impl<E, G: DOperationGenerator + 'static, T: Datagram<G = G, Error = E>> DDatagram
54    for MaybeUninit<T>
55where
56    AUTDDriverError: From<E>,
57{
58    fn dyn_operation_generator(
59        &mut self,
60        geometry: &Geometry,
61        filter: &DeviceFilter,
62        limits: &FirmwareLimits,
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, filter, limits)?))
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
84impl std::fmt::Debug for BoxedDatagram {
85    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
86        self.d.dyn_fmt(f)
87    }
88}
89
90impl BoxedDatagram {
91    /// Creates a new [`BoxedDatagram`].
92    pub fn new<E, G: DOperationGenerator + 'static, D: Datagram<G = G, Error = E> + 'static>(
93        d: D,
94    ) -> Self
95    where
96        AUTDDriverError: From<E>,
97    {
98        BoxedDatagram {
99            d: Box::new(MaybeUninit::new(d)),
100        }
101    }
102}
103
104impl Datagram for BoxedDatagram {
105    type G = DynOperationGenerator;
106    type Error = AUTDDriverError;
107
108    fn operation_generator(
109        self,
110        geometry: &Geometry,
111        filter: &DeviceFilter,
112        limits: &FirmwareLimits,
113    ) -> Result<Self::G, Self::Error> {
114        let Self { mut d } = self;
115        Ok(DynOperationGenerator {
116            g: d.dyn_operation_generator(geometry, filter, limits)?,
117        })
118    }
119
120    fn option(&self) -> DatagramOption {
121        self.d.dyn_option()
122    }
123}
124
125impl<E, O: Operation<Error = E>> DOperation for O
126where
127    AUTDDriverError: From<E>,
128{
129    fn required_size(&self, device: &Device) -> usize {
130        O::required_size(self, device)
131    }
132
133    fn pack(&mut self, device: &Device, tx: &mut [u8]) -> Result<usize, AUTDDriverError> {
134        Ok(O::pack(self, device, tx)?)
135    }
136
137    fn is_done(&self) -> bool {
138        O::is_done(self)
139    }
140}
141
142impl Operation for BoxedOperation {
143    type Error = AUTDDriverError;
144
145    fn required_size(&self, device: &Device) -> usize {
146        self.inner.required_size(device)
147    }
148
149    fn pack(&mut self, device: &Device, tx: &mut [u8]) -> Result<usize, Self::Error> {
150        self.inner.pack(device, tx)
151    }
152
153    fn is_done(&self) -> bool {
154        self.inner.is_done()
155    }
156}
157
158#[cfg(test)]
159pub mod tests {
160    use super::*;
161
162    use rand::Rng;
163
164    use autd3_core::geometry::{Point3, Transducer, UnitQuaternion};
165
166    #[derive(Clone, Copy)]
167    pub struct TestOp {
168        pub req_size: usize,
169        pub pack_size: usize,
170        pub done: bool,
171    }
172
173    impl Operation for TestOp {
174        type Error = AUTDDriverError;
175
176        fn required_size(&self, _device: &Device) -> usize {
177            self.req_size
178        }
179
180        fn pack(&mut self, _device: &Device, _tx: &mut [u8]) -> Result<usize, Self::Error> {
181            Ok(self.pack_size)
182        }
183
184        fn is_done(&self) -> bool {
185            self.done
186        }
187    }
188
189    #[test]
190    fn test_boxed_operation() {
191        let mut rng = rand::rng();
192
193        let mut op = TestOp {
194            req_size: rng.random::<u32>() as usize,
195            pack_size: rng.random::<u32>() as usize,
196            done: rng.random(),
197        };
198        let mut boxed_op = BoxedOperation {
199            inner: Box::new(op),
200        };
201
202        let device = Device::new(
203            UnitQuaternion::identity(),
204            vec![Transducer::new(Point3::origin())],
205        );
206
207        assert_eq!(
208            Operation::required_size(&op, &device),
209            Operation::required_size(&boxed_op, &device)
210        );
211        assert_eq!(
212            Operation::pack(&mut op, &device, &mut []),
213            Operation::pack(&mut boxed_op, &device, &mut [])
214        );
215        assert_eq!(Operation::is_done(&op), Operation::is_done(&boxed_op));
216    }
217}