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
86pub 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 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
138pub trait IntoBoxedDatagram {
140 #[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}