autd3_driver/firmware/driver/async/
strategy.rs

1use std::time::{Duration, Instant};
2
3use crate::firmware::driver::{FixedDelay, FixedSchedule};
4use autd3_core::sleep::r#async::Sleep;
5
6#[cfg(feature = "async-trait")]
7mod internal {
8    use super::*;
9
10    /// A trait for timer strategies.
11    #[autd3_core::async_trait]
12    pub trait TimerStrategy<S: Sleep>: Send + Sync {
13        /// Returns the initial instant.
14        fn initial(&self) -> Instant;
15        /// Sleep until the specified time.
16        /// The first call receives the return value of [`TimerStrategy::initial`] as `old`, and subsequent calls receive the previous return value.
17        async fn sleep(&self, old: Instant, interval: Duration) -> Instant;
18    }
19}
20
21#[cfg(not(feature = "async-trait"))]
22mod internal {
23    use super::*;
24
25    /// A trait for timer strategies.
26    pub trait TimerStrategy<S: Sleep>: Send {
27        /// Returns the initial instant.
28        fn initial(&self) -> Instant;
29        /// Sleep until the specified time.
30        /// The first call receives the return value of [`TimerStrategy::initial`] as `old`, and subsequent calls receive the previous return value.
31        fn sleep(
32            &self,
33            old: Instant,
34            interval: Duration,
35        ) -> impl std::future::Future<Output = Instant> + Send;
36    }
37}
38
39pub use internal::*;
40
41#[cfg_attr(feature = "async-trait", autd3_core::async_trait)]
42impl<S: Sleep> TimerStrategy<S> for FixedSchedule<S> {
43    fn initial(&self) -> Instant {
44        Instant::now()
45    }
46
47    async fn sleep(&self, old: Instant, interval: Duration) -> Instant {
48        let new = old + interval;
49        self.0
50            .sleep(new.saturating_duration_since(Instant::now()))
51            .await;
52        new
53    }
54}
55
56#[cfg_attr(feature = "async-trait", autd3_core::async_trait)]
57impl<S: Sleep> TimerStrategy<S> for FixedDelay<S> {
58    fn initial(&self) -> Instant {
59        Instant::now()
60    }
61
62    async fn sleep(&self, old: Instant, interval: Duration) -> Instant {
63        self.0.sleep(interval).await;
64        old
65    }
66}
67
68#[cfg(test)]
69mod tests {
70    use std::sync::{Arc, RwLock};
71
72    use derive_more::Debug;
73
74    use super::*;
75
76    #[derive(Debug)]
77    struct DebugSleep {
78        sleep: Arc<RwLock<Vec<Duration>>>,
79    }
80
81    #[cfg_attr(feature = "async-trait", autd3_core::async_trait)]
82    impl Sleep for DebugSleep {
83        async fn sleep(&self, duration: Duration) {
84            self.sleep.write().unwrap().push(duration);
85        }
86    }
87
88    #[tokio::test]
89    async fn fixed_schedule_test() {
90        let sleep = Arc::new(RwLock::new(Vec::new()));
91
92        let strategy = FixedSchedule(DebugSleep { sleep });
93
94        let start = strategy.initial();
95        let interval = Duration::from_millis(1);
96
97        let next = strategy.sleep(start, interval).await;
98        assert_eq!(next, start + interval);
99
100        let next = strategy.sleep(next, interval).await;
101        assert_eq!(next, start + interval * 2);
102    }
103
104    #[tokio::test]
105    async fn fixed_delay_test() {
106        let sleep = Arc::new(RwLock::new(Vec::new()));
107
108        let strategy = FixedDelay(DebugSleep {
109            sleep: sleep.clone(),
110        });
111
112        let start = strategy.initial();
113        let interval = Duration::from_millis(1);
114
115        let next = strategy.sleep(start, interval).await;
116        assert_eq!(next, start);
117
118        let next = strategy.sleep(start, interval).await;
119        assert_eq!(next, start);
120
121        assert_eq!(*sleep.read().unwrap(), vec![interval, interval]);
122    }
123}