]> git.lizzy.rs Git - rust.git/blob - library/std/src/sys/itron/time.rs
Merge commit 'b52fb5234cd7c11ecfae51897a6f7fa52e8777fc' into clippyup
[rust.git] / library / std / src / sys / itron / time.rs
1 use super::{abi, error::expect_success};
2 use crate::{mem::MaybeUninit, time::Duration};
3
4 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
5 pub struct Instant(abi::SYSTIM);
6
7 impl Instant {
8     pub fn now() -> Instant {
9         // Safety: The provided pointer is valid
10         unsafe {
11             let mut out = MaybeUninit::uninit();
12             expect_success(abi::get_tim(out.as_mut_ptr()), &"get_tim");
13             Instant(out.assume_init())
14         }
15     }
16
17     pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
18         self.0.checked_sub(other.0).map(|ticks| {
19             // `SYSTIM` is measured in microseconds
20             Duration::from_micros(ticks)
21         })
22     }
23
24     pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
25         // `SYSTIM` is measured in microseconds
26         let ticks = other.as_micros();
27
28         Some(Instant(self.0.checked_add(ticks.try_into().ok()?)?))
29     }
30
31     pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
32         // `SYSTIM` is measured in microseconds
33         let ticks = other.as_micros();
34
35         Some(Instant(self.0.checked_sub(ticks.try_into().ok()?)?))
36     }
37 }
38
39 /// Split `Duration` into zero or more `RELTIM`s.
40 #[inline]
41 pub fn dur2reltims(dur: Duration) -> impl Iterator<Item = abi::RELTIM> {
42     // `RELTIM` is microseconds
43     let mut ticks = dur.as_micros();
44
45     crate::iter::from_fn(move || {
46         if ticks == 0 {
47             None
48         } else if ticks <= abi::TMAX_RELTIM as u128 {
49             Some(crate::mem::replace(&mut ticks, 0) as abi::RELTIM)
50         } else {
51             ticks -= abi::TMAX_RELTIM as u128;
52             Some(abi::TMAX_RELTIM)
53         }
54     })
55 }
56
57 /// Split `Duration` into one or more `TMO`s.
58 #[inline]
59 fn dur2tmos(dur: Duration) -> impl Iterator<Item = abi::TMO> {
60     // `TMO` is microseconds
61     let mut ticks = dur.as_micros();
62     let mut end = false;
63
64     crate::iter::from_fn(move || {
65         if end {
66             None
67         } else if ticks <= abi::TMAX_RELTIM as u128 {
68             end = true;
69             Some(crate::mem::replace(&mut ticks, 0) as abi::TMO)
70         } else {
71             ticks -= abi::TMAX_RELTIM as u128;
72             Some(abi::TMAX_RELTIM)
73         }
74     })
75 }
76
77 /// Split `Duration` into one or more API calls with timeout.
78 #[inline]
79 pub fn with_tmos(dur: Duration, mut f: impl FnMut(abi::TMO) -> abi::ER) -> abi::ER {
80     let mut er = abi::E_TMOUT;
81     for tmo in dur2tmos(dur) {
82         er = f(tmo);
83         if er != abi::E_TMOUT {
84             break;
85         }
86     }
87     er
88 }
89
90 /// Split `Duration` into one or more API calls with timeout. This function can
91 /// handle spurious wakeups.
92 #[inline]
93 pub fn with_tmos_strong(dur: Duration, mut f: impl FnMut(abi::TMO) -> abi::ER) -> abi::ER {
94     // `TMO` and `SYSTIM` are microseconds.
95     // Clamp at `SYSTIM::MAX` for performance reasons. This shouldn't cause
96     // a problem in practice. (`u64::MAX` μs ≈ 584942 years)
97     let ticks = dur.as_micros().min(abi::SYSTIM::MAX as u128) as abi::SYSTIM;
98
99     let start = Instant::now().0;
100     let mut elapsed = 0;
101     let mut er = abi::E_TMOUT;
102     while elapsed <= ticks {
103         er = f(elapsed.min(abi::TMAX_RELTIM as abi::SYSTIM) as abi::TMO);
104         if er != abi::E_TMOUT {
105             break;
106         }
107         elapsed = Instant::now().0.wrapping_sub(start);
108     }
109
110     er
111 }
112
113 #[cfg(test)]
114 mod tests;