autd3_driver/datagram/
boxed.rs1use 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) -> (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) -> (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) -> (BoxedOperation, BoxedOperation) {
43 let (o1, o2) = self.generate(device);
44 (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: &Geometry,
52 parallel: bool,
53 ) -> Result<DynDOperationGenerator, AUTDDriverError>;
54 #[must_use]
55 fn dyn_option(&self) -> DatagramOption;
56 fn dyn_fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result;
57}
58
59impl<
60 E,
61 #[cfg(feature = "lightweight")] G: DOperationGenerator + Send + 'static,
62 #[cfg(not(feature = "lightweight"))] G: DOperationGenerator + 'static,
63 T: Datagram<G = G, Error = E>,
64> DDatagram for MaybeUninit<T>
65where
66 AUTDDriverError: From<E>,
67{
68 fn dyn_operation_generator(
69 &mut self,
70 geometry: &Geometry,
71 parallel: bool,
72 ) -> Result<DynDOperationGenerator, AUTDDriverError> {
73 let mut tmp = MaybeUninit::<T>::uninit();
74 std::mem::swap(&mut tmp, self);
75 let d = unsafe { tmp.assume_init() };
76 Ok(Box::new(d.operation_generator(geometry, parallel)?))
77 }
78
79 fn dyn_option(&self) -> DatagramOption {
80 unsafe { self.assume_init_ref() }.option()
81 }
82
83 fn dyn_fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
84 unsafe { self.assume_init_ref() }.fmt(f)
85 }
86}
87
88pub struct BoxedDatagram {
90 d: Box<dyn DDatagram>,
91}
92
93#[cfg(feature = "lightweight")]
94unsafe impl Send for BoxedDatagram {}
95#[cfg(feature = "lightweight")]
96unsafe impl Sync for BoxedDatagram {}
97
98impl std::fmt::Debug for BoxedDatagram {
99 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
100 self.d.dyn_fmt(f)
101 }
102}
103
104impl BoxedDatagram {
105 fn new<
106 E,
107 #[cfg(feature = "lightweight")] G: OperationGenerator + Send + 'static,
108 #[cfg(not(feature = "lightweight"))] G: OperationGenerator + 'static,
109 D: Datagram<G = G, Error = E> + 'static,
110 >(
111 d: D,
112 ) -> Self
113 where
114 AUTDDriverError: From<E>,
115 AUTDDriverError: From<<G::O1 as Operation>::Error> + From<<G::O2 as Operation>::Error>,
116 {
117 BoxedDatagram {
118 d: Box::new(MaybeUninit::new(d)),
119 }
120 }
121}
122
123impl Datagram for BoxedDatagram {
124 type G = DynOperationGenerator;
125 type Error = AUTDDriverError;
126
127 fn operation_generator(
128 self,
129 geometry: &Geometry,
130 parallel: bool,
131 ) -> Result<Self::G, Self::Error> {
132 let Self { mut d } = self;
133 Ok(DynOperationGenerator {
134 g: d.dyn_operation_generator(geometry, parallel)?,
135 })
136 }
137
138 fn option(&self) -> DatagramOption {
139 self.d.dyn_option()
140 }
141}
142
143pub trait IntoBoxedDatagram {
145 #[must_use]
147 fn into_boxed(self) -> BoxedDatagram;
148}
149
150impl<
151 E,
152 #[cfg(feature = "lightweight")] G: OperationGenerator + Send + 'static,
153 #[cfg(not(feature = "lightweight"))] G: OperationGenerator + 'static,
154 #[cfg(feature = "lightweight")] D: Datagram<Error = E, G = G> + Send + 'static,
155 #[cfg(not(feature = "lightweight"))] D: Datagram<Error = E, G = G> + 'static,
156> IntoBoxedDatagram for D
157where
158 AUTDDriverError: From<E>,
159 AUTDDriverError: From<<G::O1 as Operation>::Error> + From<<G::O2 as Operation>::Error>,
160{
161 fn into_boxed(self) -> BoxedDatagram {
162 BoxedDatagram::new(self)
163 }
164}
165
166#[cfg(test)]
167mod tests {
168
169 use super::*;
170
171 struct TestDatagram;
173 struct TestOperationGenerator;
174
175 impl OperationGenerator for TestOperationGenerator {
176 type O1 = autd3_core::datagram::NullOp;
177 type O2 = autd3_core::datagram::NullOp;
178
179 fn generate(&mut self, _device: &Device) -> (Self::O1, Self::O2) {
180 unimplemented!()
181 }
182 }
183
184 impl Datagram for TestDatagram {
185 type G = TestOperationGenerator;
186 type Error = AUTDDriverError;
187
188 fn operation_generator(
189 self,
190 _geometry: &Geometry,
191 _parallel: bool,
192 ) -> Result<Self::G, Self::Error> {
193 Ok(Self::G {})
194 }
195 }
196 impl std::fmt::Debug for TestDatagram {
199 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
200 write!(f, "test")
201 }
202 }
203
204 #[test]
205 fn boxed_fmt() {
206 let d = TestDatagram;
207 let bd = BoxedDatagram::new(d);
208 assert_eq!(format!("{:?}", bd), "test");
209 }
210}