pw_time_core/
pw_time_core.rs1#![no_std]
15
16use core::marker::PhantomData;
26use core::ops::{Add, Sub};
27
28#[cfg(test)]
29#[unsafe(no_mangle)]
30unsafe extern "C-unwind" fn pw_assert_HandleFailure() -> ! {
31 panic!("pw_assert failed");
32}
33
34pub trait Clock: Sized {
36 const TICKS_PER_SEC: u64;
38
39 fn now() -> Instant<Self>;
41}
42
43#[derive(Debug)]
48pub struct Instant<Clock: crate::Clock> {
49 ticks: u64,
50 _phantom: PhantomData<Clock>,
51}
52
53impl<Clock: crate::Clock> Instant<Clock> {
54 pub const MAX: Self = Self::from_ticks(u64::MAX);
56 pub const MIN: Self = Self::from_ticks(u64::MIN);
58
59 #[must_use]
61 pub const fn from_ticks(ticks: u64) -> Self {
62 Self {
63 ticks,
64 _phantom: PhantomData,
65 }
66 }
67
68 #[must_use]
70 pub const fn ticks(&self) -> u64 {
71 self.ticks
72 }
73
74 #[must_use]
76 pub const fn checked_add_duration(self, duration: Duration<Clock>) -> Option<Self> {
77 if let Some(ticks) = self.ticks.checked_add_signed(duration.ticks) {
78 Some(Self {
79 ticks,
80 _phantom: PhantomData,
81 })
82 } else {
83 None
84 }
85 }
86
87 #[must_use]
89 pub const fn checked_sub_duration(self, duration: Duration<Clock>) -> Option<Self> {
90 if let Some(ticks) = self.ticks.checked_add_signed(-duration.ticks) {
91 Some(Self {
92 ticks,
93 _phantom: PhantomData,
94 })
95 } else {
96 None
97 }
98 }
99}
100
101impl<Clock: crate::Clock> Copy for Instant<Clock> {}
103
104impl<Clock: crate::Clock> Clone for Instant<Clock> {
106 fn clone(&self) -> Self {
107 *self
108 }
109}
110
111impl<Clock: crate::Clock> Ord for Instant<Clock> {
113 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
114 self.ticks.cmp(&other.ticks)
115 }
116}
117
118impl<Clock: crate::Clock> PartialOrd for Instant<Clock> {
120 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
121 Some(self.cmp(other))
122 }
123}
124
125impl<Clock: crate::Clock> Eq for Instant<Clock> {}
127
128impl<Clock: crate::Clock> PartialEq for Instant<Clock> {
130 fn eq(&self, other: &Self) -> bool {
131 self.ticks == other.ticks
132 }
133}
134
135impl<Clock: crate::Clock> Sub<Instant<Clock>> for Instant<Clock> {
136 type Output = Duration<Clock>;
137
138 fn sub(self, rhs: Instant<Clock>) -> Self::Output {
139 Self::Output {
140 ticks: self.ticks.wrapping_sub(rhs.ticks).cast_signed(),
143 _phantom: PhantomData,
144 }
145 }
146}
147
148impl<Clock: crate::Clock> Add<Duration<Clock>> for Instant<Clock> {
149 type Output = Instant<Clock>;
150
151 fn add(self, rhs: Duration<Clock>) -> Self::Output {
152 let time = self.checked_add_duration(rhs);
153 if time.is_none() {
154 pw_assert::panic!("Instant - Duration overflow");
155 }
156 time.unwrap()
157 }
158}
159
160impl<Clock: crate::Clock> Sub<Duration<Clock>> for Instant<Clock> {
161 type Output = Instant<Clock>;
162
163 fn sub(self, rhs: Duration<Clock>) -> Self::Output {
164 let time = self.checked_sub_duration(rhs);
165 if time.is_none() {
166 pw_assert::panic!("Instant - Duration overflow")
167 }
168 time.unwrap()
169 }
170}
171
172#[derive(Debug)]
177pub struct Duration<Clock: crate::Clock> {
178 ticks: i64,
179 _phantom: PhantomData<Clock>,
180}
181
182impl<Clock: crate::Clock> Duration<Clock> {
183 pub const MAX: Self = Self {
185 ticks: i64::MAX,
186 _phantom: PhantomData,
187 };
188
189 pub const MIN: Self = Self {
191 ticks: i64::MIN,
192 _phantom: PhantomData,
193 };
194
195 #[must_use]
197 pub const fn ticks(self) -> i64 {
198 self.ticks
199 }
200
201 #[must_use]
203 pub const fn from_secs(secs: i64) -> Self {
204 Self {
205 ticks: secs * (Clock::TICKS_PER_SEC.cast_signed()),
206 _phantom: PhantomData,
207 }
208 }
209
210 #[must_use]
212 pub const fn from_millis(millis: i64) -> Self {
213 Self {
214 ticks: millis * (Clock::TICKS_PER_SEC.cast_signed()) / 1000,
215 _phantom: PhantomData,
216 }
217 }
218
219 #[must_use]
221 pub const fn from_micros(micros: i64) -> Self {
222 Self {
223 ticks: micros * (Clock::TICKS_PER_SEC.cast_signed()) / 1_000_000,
224 _phantom: PhantomData,
225 }
226 }
227
228 #[must_use]
230 pub const fn from_nanos(nanos: i64) -> Self {
231 Self {
232 ticks: nanos * (Clock::TICKS_PER_SEC.cast_signed()) / 1_000_000_000,
233 _phantom: PhantomData,
234 }
235 }
236
237 #[must_use]
239 pub const fn checked_add(self, rhs: Duration<Clock>) -> Option<Self> {
240 if let Some(ticks) = self.ticks.checked_add(rhs.ticks) {
241 Some(Self {
242 ticks,
243 _phantom: PhantomData,
244 })
245 } else {
246 None
247 }
248 }
249
250 #[must_use]
252 pub const fn checked_sub(self, rhs: Duration<Clock>) -> Option<Self> {
253 if let Some(ticks) = self.ticks.checked_sub(rhs.ticks) {
254 Some(Self {
255 ticks,
256 _phantom: PhantomData,
257 })
258 } else {
259 None
260 }
261 }
262}
263
264impl<Clock: crate::Clock> Copy for Duration<Clock> {}
266
267impl<Clock: crate::Clock> Clone for Duration<Clock> {
269 fn clone(&self) -> Self {
270 *self
271 }
272}
273
274impl<Clock: crate::Clock> Ord for Duration<Clock> {
276 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
277 self.ticks.cmp(&other.ticks)
278 }
279}
280
281impl<Clock: crate::Clock> PartialOrd for Duration<Clock> {
283 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
284 Some(self.cmp(other))
285 }
286}
287
288impl<Clock: crate::Clock> Eq for Duration<Clock> {}
290
291impl<Clock: crate::Clock> PartialEq for Duration<Clock> {
293 fn eq(&self, other: &Self) -> bool {
294 self.ticks == other.ticks
295 }
296}
297
298impl<Clock: crate::Clock> Sub<Duration<Clock>> for Duration<Clock> {
299 type Output = Duration<Clock>;
300
301 fn sub(self, rhs: Duration<Clock>) -> Self::Output {
302 let time = self.checked_sub(rhs);
303 if time.is_none() {
304 pw_assert::panic!("Duration subtraction overflow")
305 }
306 time.unwrap()
307 }
308}
309
310impl<Clock: crate::Clock> Add<Duration<Clock>> for Duration<Clock> {
311 type Output = Duration<Clock>;
312
313 fn add(self, rhs: Duration<Clock>) -> Self::Output {
314 let time = self.checked_add(rhs);
315 if time.is_none() {
316 pw_assert::panic!("Duration addition overflow")
317 }
318 time.unwrap()
319 }
320}
321
322#[cfg(test)]
323mod tests {
324 use super::*;
325
326 #[derive(Debug)]
327 struct TestClock;
328
329 impl Clock for TestClock {
330 const TICKS_PER_SEC: u64 = 1_000;
331 fn now() -> Instant<Self> {
332 Instant::from_ticks(0)
333 }
334 }
335
336 #[derive(Debug)]
337 struct HighResTestClock;
338
339 impl Clock for HighResTestClock {
340 const TICKS_PER_SEC: u64 = 1_000_000_000;
341 fn now() -> Instant<Self> {
342 Instant::from_ticks(0)
343 }
344 }
345
346 #[test]
347 fn duration_constructors_return_correct_values() {
348 assert_eq!(Duration::<TestClock>::from_secs(1234).ticks(), 1_234_000);
349 assert_eq!(Duration::<TestClock>::from_millis(1234).ticks(), 1_234);
350 assert_eq!(Duration::<TestClock>::from_micros(1234).ticks(), 1);
351 assert_eq!(Duration::<TestClock>::from_nanos(1234).ticks(), 0);
352
353 assert_eq!(Duration::<HighResTestClock>::from_nanos(1234).ticks(), 1234);
354 }
355
356 #[test]
357 fn duration_checked_addition_returns_correct_values() {
358 let ten_ms = Duration::<TestClock>::from_millis(10);
359 let one_ms = Duration::<TestClock>::from_millis(1);
360
361 assert_eq!(
362 ten_ms.checked_add(one_ms),
363 Some(Duration::<TestClock>::from_millis(11))
364 );
365
366 assert_eq!(
367 one_ms.checked_add(ten_ms),
368 Some(Duration::<TestClock>::from_millis(11))
369 );
370
371 assert_eq!(Duration::<TestClock>::MAX.checked_add(one_ms), None);
372
373 assert_eq!(
374 Duration::<TestClock>::MIN.checked_add(Duration::from_millis(-1)),
375 None
376 );
377 }
378
379 #[test]
380 fn duration_checked_subtraction_returns_correct_values() {
381 let ten_ms = Duration::<TestClock>::from_millis(10);
382 let one_ms = Duration::<TestClock>::from_millis(1);
383
384 assert_eq!(
385 ten_ms.checked_sub(one_ms),
386 Some(Duration::<TestClock>::from_millis(9))
387 );
388
389 assert_eq!(
390 one_ms.checked_sub(ten_ms),
391 Some(Duration::<TestClock>::from_millis(-9))
392 );
393
394 assert_eq!(
395 Duration::<TestClock>::MAX.checked_sub(Duration::from_millis(-1)),
396 None
397 );
398
399 assert_eq!(
400 Duration::<TestClock>::MIN.checked_sub(Duration::from_millis(1)),
401 None
402 );
403 }
404
405 #[test]
406 fn instant_subtraction_returns_correct_values() {
407 let ten_ms = Instant::from_ticks(10 * <TestClock as Clock>::TICKS_PER_SEC / 1000);
408 let one_ms = Instant::from_ticks(<TestClock as Clock>::TICKS_PER_SEC / 1000);
409
410 assert_eq!(ten_ms - one_ms, Duration::<TestClock>::from_millis(9));
411 assert_eq!(one_ms - ten_ms, Duration::<TestClock>::from_millis(-9));
412 }
413
414 #[test]
415 fn instant_checked_duration_addition_returns_correct_values() {
416 let instant_eleven_ms =
417 Instant::<TestClock>::from_ticks(11 * <TestClock as Clock>::TICKS_PER_SEC / 1000);
418 let instant_ten_ms =
419 Instant::<TestClock>::from_ticks(10 * <TestClock as Clock>::TICKS_PER_SEC / 1000);
420 let instant_nine_ms =
421 Instant::<TestClock>::from_ticks(9 * <TestClock as Clock>::TICKS_PER_SEC / 1000);
422
423 let duration_one_ms = Duration::<TestClock>::from_millis(1);
424 let duration_minus_one_ms = Duration::<TestClock>::from_millis(-1);
425
426 assert_eq!(
427 instant_ten_ms.checked_add_duration(duration_one_ms),
428 Some(instant_eleven_ms)
429 );
430
431 assert_eq!(
432 instant_ten_ms.checked_add_duration(duration_minus_one_ms),
433 Some(instant_nine_ms)
434 );
435
436 assert_eq!(
437 Instant::<TestClock>::MAX.checked_add_duration(duration_one_ms),
438 None
439 );
440
441 assert_eq!(
442 Instant::<TestClock>::MIN.checked_add_duration(duration_minus_one_ms),
443 None
444 );
445 }
446
447 #[test]
448 fn instant_checked_duration_subtraction_returns_correct_values() {
449 let instant_eleven_ms =
450 Instant::<TestClock>::from_ticks(11 * <TestClock as Clock>::TICKS_PER_SEC / 1000);
451 let instant_ten_ms =
452 Instant::<TestClock>::from_ticks(10 * <TestClock as Clock>::TICKS_PER_SEC / 1000);
453 let instant_nine_ms =
454 Instant::<TestClock>::from_ticks(9 * <TestClock as Clock>::TICKS_PER_SEC / 1000);
455
456 let duration_one_ms = Duration::<TestClock>::from_millis(1);
457 let duration_minus_one_ms = Duration::<TestClock>::from_millis(-1);
458
459 assert_eq!(
460 instant_ten_ms.checked_sub_duration(duration_one_ms),
461 Some(instant_nine_ms)
462 );
463
464 assert_eq!(
465 instant_ten_ms.checked_sub_duration(duration_minus_one_ms),
466 Some(instant_eleven_ms)
467 );
468
469 assert_eq!(
470 Instant::<TestClock>::MAX.checked_sub_duration(duration_minus_one_ms),
471 None
472 );
473
474 assert_eq!(
475 Instant::<TestClock>::MIN.checked_sub_duration(duration_one_ms),
476 None
477 );
478 }
479}