autd3_driver/firmware/operation/implement/
boxed.rs1use 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
77pub struct BoxedDatagram {
79 d: Box<dyn DDatagram>,
80}
81
82impl BoxedDatagram {
83 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}