1use std::future::{Future, IntoFuture};
4
5use futures::future::{Either, TryFutureExt};
6use veecle_osal_api::Error;
7pub use veecle_osal_api::time::{
8 Duration, Exceeded, Instant, Interval, SystemTime, SystemTimeError, SystemTimeSync,
9 TimeAbstraction,
10};
11
12#[derive(Debug)]
17pub struct Time;
18
19impl TimeAbstraction for Time {
20 fn now() -> Instant {
21 use std::sync::LazyLock;
22 static EPOCH: LazyLock<std::time::Instant> = LazyLock::new(std::time::Instant::now);
23 Instant::MIN
24 + Duration::try_from(EPOCH.elapsed())
25 .expect("time elapsed since start is less than 2^64-1 microseconds")
26 }
27
28 async fn sleep(duration: Duration) -> Result<(), Error> {
29 let duration = std::time::Duration::from_millis(duration.as_millis());
30 tokio::time::sleep(duration).await;
31 Ok(())
32 }
33
34 async fn sleep_until(deadline: Instant) -> Result<(), Error> {
35 Self::sleep(
36 deadline
37 .duration_since(Self::now())
38 .unwrap_or(Duration::ZERO),
39 )
40 .await
41 }
42
43 fn timeout_at<F>(
44 deadline: Instant,
45 future: F,
46 ) -> impl Future<Output = Result<F::Output, Either<Exceeded, Error>>>
47 where
48 Self: Sized,
49 F: IntoFuture,
50 {
51 let duration = deadline
52 .duration_since(Self::now())
53 .map(|duration| std::time::Duration::from_millis(duration.as_millis()))
54 .unwrap_or(std::time::Duration::ZERO);
55
56 tokio::time::timeout(duration, future).map_err(|_elapsed| Either::Left(Exceeded))
57 }
58
59 fn interval(period: Duration) -> impl Interval
60 where
61 Self: Sized,
62 {
63 struct IntervalInternal(tokio::time::Interval);
64
65 impl Interval for IntervalInternal {
66 async fn tick(&mut self) -> Result<(), Error> {
67 self.0.tick().await;
68 Ok(())
69 }
70 }
71
72 let period = std::time::Duration::from_millis(period.as_millis());
73 IntervalInternal(tokio::time::interval(period))
74 }
75}
76
77impl SystemTime for Time {
78 fn duration_since_epoch() -> Result<Duration, SystemTimeError> {
79 let std_duration_since_epoch = std::time::SystemTime::now()
80 .duration_since(std::time::SystemTime::UNIX_EPOCH)
81 .expect("SystemTime::now() should not be less then UNIX_EPOCH");
82 Ok(Duration::from_millis(
83 std_duration_since_epoch.as_millis() as u64
84 ))
85 }
86}
87
88#[cfg(all(test, not(miri)))]
89mod tests {
90 use core::pin::pin;
91
92 use futures::future::{Either, FutureExt};
93 use veecle_osal_api::time::{Duration, Exceeded, Interval, SystemTime, TimeAbstraction};
94
95 use crate::time::Time;
96
97 #[test]
98 fn test_std_system_time_duration_since_epoch() {
99 let a = Time::duration_since_epoch().unwrap_or_default();
100 let b = Time::duration_since_epoch().unwrap_or_default();
101 assert!(b.as_millis() - a.as_millis() < 100);
102
103 let sleep_time = 200;
104 std::thread::sleep(std::time::Duration::from_millis(sleep_time));
105
106 let c = Time::duration_since_epoch().unwrap_or_default();
107 assert!(c.as_millis() - a.as_millis() >= sleep_time);
108 assert!(c.as_millis() - a.as_millis() < sleep_time + 100);
109 }
110
111 #[tokio::test(start_paused = true)]
112 async fn sleep_until_smoke_test() {
113 let mut sleep = pin!(Time::sleep_until(Time::now() + Duration::from_secs(5)));
114
115 assert!(sleep.as_mut().now_or_never().is_none());
116
117 tokio::time::advance(std::time::Duration::from_secs(2)).await;
118
119 assert!(sleep.as_mut().now_or_never().is_none());
120
121 tokio::time::advance(std::time::Duration::from_secs(4)).await;
122
123 assert!(matches!(sleep.as_mut().now_or_never(), Some(Ok(()))));
124 }
125
126 #[tokio::test(start_paused = true)]
127 async fn sleep_smoke_test() {
128 let mut sleep = pin!(Time::sleep(Duration::from_secs(5)));
129
130 assert!(sleep.as_mut().now_or_never().is_none());
131
132 tokio::time::advance(std::time::Duration::from_secs(2)).await;
133
134 assert!(sleep.as_mut().now_or_never().is_none());
135
136 tokio::time::advance(std::time::Duration::from_secs(4)).await;
137
138 assert!(matches!(sleep.as_mut().now_or_never(), Some(Ok(()))));
139 }
140
141 #[tokio::test(start_paused = true)]
142 async fn sleep_max_test() {
143 let mut sleep = pin!(Time::sleep(Duration::MAX));
144
145 assert!(sleep.as_mut().now_or_never().is_none());
146
147 tokio::time::advance(std::time::Duration::from_secs(2)).await;
148
149 assert!(sleep.as_mut().now_or_never().is_none());
150
151 tokio::time::advance(std::time::Duration::from_secs(60 * 60 * 24 * 7 * 52 * 20)).await;
152
153 assert!(sleep.as_mut().now_or_never().is_none());
154 }
155
156 #[tokio::test(start_paused = true)]
157 async fn timeout_at_smoke_test() {
158 let mut future = pin!(Time::timeout_at(
159 Time::now() + Duration::from_secs(10),
160 Time::sleep_until(Time::now() + Duration::from_secs(5))
161 ));
162
163 assert!(future.as_mut().now_or_never().is_none());
164
165 tokio::time::advance(std::time::Duration::from_secs(2)).await;
166
167 assert!(future.as_mut().now_or_never().is_none());
168
169 tokio::time::advance(std::time::Duration::from_secs(4)).await;
170
171 assert!(matches!(future.as_mut().now_or_never(), Some(Ok(Ok(())))));
172 }
173
174 #[tokio::test(start_paused = true)]
175 async fn timeout_at_smoke_test_exceeded() {
176 let mut future = pin!(Time::timeout_at(
177 Time::now() + Duration::from_secs(5),
178 std::future::pending::<()>()
179 ));
180
181 assert!(future.as_mut().now_or_never().is_none());
182
183 tokio::time::advance(std::time::Duration::from_secs(2)).await;
184
185 assert!(future.as_mut().now_or_never().is_none());
186
187 tokio::time::advance(std::time::Duration::from_secs(4)).await;
188
189 assert!(matches!(
190 future.as_mut().now_or_never(),
191 Some(Err(Either::Left(Exceeded)))
192 ));
193 }
194
195 #[tokio::test(start_paused = true)]
196 async fn interval_smoke_test() {
197 let mut interval = Time::interval(Duration::from_secs(5));
198
199 assert!(matches!(interval.tick().now_or_never(), Some(Ok(()))));
200
201 assert!(interval.tick().now_or_never().is_none());
202
203 tokio::time::advance(std::time::Duration::from_secs(2)).await;
204
205 assert!(interval.tick().now_or_never().is_none());
206
207 tokio::time::advance(std::time::Duration::from_secs(4)).await;
208
209 assert!(matches!(interval.tick().now_or_never(), Some(Ok(()))));
210
211 assert!(interval.tick().now_or_never().is_none());
212
213 tokio::time::advance(std::time::Duration::from_secs(2)).await;
214
215 assert!(interval.tick().now_or_never().is_none());
216
217 tokio::time::advance(std::time::Duration::from_secs(3)).await;
218
219 assert!(matches!(interval.tick().now_or_never(), Some(Ok(()))));
220 }
221}