autd3_core/datagram/
tuple.rs

1use thiserror::Error;
2
3use crate::geometry::Geometry;
4
5use super::{Datagram, DatagramOption};
6
7#[derive(Debug, PartialEq)]
8#[doc(hidden)]
9pub struct CombinedOperationGenerator<O1, O2> {
10    pub o1: O1,
11    pub o2: O2,
12}
13
14#[derive(Error, Debug, PartialEq)]
15#[doc(hidden)]
16pub enum CombinedError<E1, E2> {
17    #[error("{0}")]
18    E1(E1),
19    #[error("{0}")]
20    E2(E2),
21}
22
23impl<G1, G2, D1, D2, E1, E2> Datagram for (D1, D2)
24where
25    D1: Datagram<G = G1, Error = E1>,
26    D2: Datagram<G = G2, Error = E2>,
27{
28    type G = CombinedOperationGenerator<D1::G, D2::G>;
29    type Error = CombinedError<E1, E2>;
30
31    fn operation_generator(
32        self,
33        geometry: &Geometry,
34        parallel: bool,
35    ) -> Result<Self::G, Self::Error> {
36        match (
37            self.0.operation_generator(geometry, parallel),
38            self.1.operation_generator(geometry, parallel),
39        ) {
40            (Ok(g1), Ok(g2)) => Ok(CombinedOperationGenerator { o1: g1, o2: g2 }),
41            (Err(e1), _) => Err(Self::Error::E1(e1)),
42            (_, Err(e2)) => Err(Self::Error::E2(e2)),
43        }
44    }
45
46    fn option(&self) -> DatagramOption {
47        DatagramOption {
48            timeout: self.0.option().timeout.max(self.1.option().timeout),
49            parallel_threshold: self
50                .0
51                .option()
52                .parallel_threshold
53                .min(self.1.option().parallel_threshold),
54        }
55    }
56}
57
58#[cfg(test)]
59mod tests {
60    use super::*;
61
62    use std::time::Duration;
63
64    #[derive(Debug)]
65    pub struct TestDatagram {
66        pub option: DatagramOption,
67        pub result: Result<(), ()>,
68    }
69
70    impl Datagram for TestDatagram {
71        type G = ();
72        type Error = ();
73
74        fn operation_generator(self, _: &Geometry, _: bool) -> Result<Self::G, Self::Error> {
75            self.result
76        }
77
78        fn option(&self) -> DatagramOption {
79            self.option
80        }
81    }
82
83    #[rstest::rstest]
84    #[case(Ok(CombinedOperationGenerator { o1: (), o2: () }), Ok(()), Ok(()))]
85    #[case(Err(CombinedError::E1(())), Err(()), Ok(()))]
86    #[case(Err(CombinedError::E2(())), Ok(()), Err(()))]
87    #[test]
88    fn operation_generator(
89        #[case] expect: Result<CombinedOperationGenerator<(), ()>, CombinedError<(), ()>>,
90        #[case] result1: Result<(), ()>,
91        #[case] result2: Result<(), ()>,
92    ) {
93        assert_eq!(
94            expect,
95            (
96                TestDatagram {
97                    option: DatagramOption::default(),
98                    result: result1,
99                },
100                TestDatagram {
101                    option: DatagramOption::default(),
102                    result: result2,
103                }
104            )
105                .operation_generator(&Geometry::new(Default::default()), false)
106        );
107    }
108
109    #[rstest::rstest]
110    #[case(
111        Duration::from_millis(200),
112        Duration::from_millis(100),
113        Duration::from_millis(200)
114    )]
115    #[case(
116        Duration::from_millis(200),
117        Duration::from_millis(200),
118        Duration::from_millis(100)
119    )]
120    #[test]
121    fn timeout(#[case] expect: Duration, #[case] timeout1: Duration, #[case] timeout2: Duration) {
122        assert_eq!(
123            expect,
124            (
125                TestDatagram {
126                    option: DatagramOption {
127                        timeout: timeout1,
128                        parallel_threshold: 0,
129                    },
130                    result: Ok(()),
131                },
132                TestDatagram {
133                    option: DatagramOption {
134                        timeout: timeout2,
135                        parallel_threshold: 0,
136                    },
137                    result: Ok(()),
138                }
139            )
140                .option()
141                .timeout
142        );
143    }
144
145    #[rstest::rstest]
146    #[case(100, 100, 200)]
147    #[case(100, 200, 100)]
148    #[test]
149    fn parallel_threshold(
150        #[case] expect: usize,
151        #[case] threshold1: usize,
152        #[case] threshold2: usize,
153    ) {
154        assert_eq!(
155            expect,
156            (
157                TestDatagram {
158                    option: DatagramOption {
159                        timeout: Duration::ZERO,
160                        parallel_threshold: threshold1,
161                    },
162                    result: Ok(()),
163                },
164                TestDatagram {
165                    option: DatagramOption {
166                        timeout: Duration::ZERO,
167                        parallel_threshold: threshold2,
168                    },
169                    result: Ok(()),
170                }
171            )
172                .option()
173                .parallel_threshold
174        );
175    }
176}