waiter_trait/
std_impls.rs

1use super::*;
2use std::{
3    thread::{sleep, yield_now},
4    time::{Duration, Instant},
5};
6
7/// [`Waiter`] implementation for `std`.
8///
9/// # Examples
10///
11/// ```
12/// use std::time::Duration;
13/// use waiter_trait::{Waiter, WaiterStatus, StdWaiter, StdInterval};
14///
15/// let w = StdWaiter::new(Duration::from_millis(10), StdInterval::new(Duration::from_millis(10)));
16/// let mut t = w.start();
17/// assert!(!t.timeout());
18/// assert!(t.timeout());
19///
20/// t.restart();
21/// assert!(!t.timeout());
22/// assert!(t.timeout());
23/// ```
24pub struct StdWaiter<I> {
25    timeout: Duration,
26    interval: I,
27}
28
29impl<I: Interval> StdWaiter<I> {
30    /// - `timeout`
31    /// - `interval`: Before the time limit expires,
32    ///   this action will execute each time `timeout()` is called.
33    pub fn new(timeout: Duration, interval: I) -> Self {
34        Self { timeout, interval }
35    }
36}
37
38impl<I: Interval> Waiter for StdWaiter<I> {
39    #[inline]
40    fn start(&self) -> impl WaiterStatus {
41        StdWaiterStatus {
42            start_time: Instant::now(),
43            waiter: self,
44        }
45    }
46}
47
48/// [`WaiterStatus`] implementation for `std`.
49pub struct StdWaiterStatus<'a, I> {
50    start_time: Instant,
51    waiter: &'a StdWaiter<I>,
52}
53
54impl<'a, I: Interval> WaiterStatus for StdWaiterStatus<'a, I> {
55    #[inline]
56    fn timeout(&mut self) -> bool {
57        if self.start_time.elapsed() >= self.waiter.timeout {
58            true
59        } else {
60            self.waiter.interval.interval();
61            false
62        }
63    }
64
65    #[inline(always)]
66    fn restart(&mut self) {
67        self.start_time = Instant::now();
68    }
69}
70
71impl TickInstant for Instant {
72    #[inline(always)]
73    fn now() -> Self {
74        Instant::now()
75    }
76
77    #[inline(always)]
78    fn tick_since(self, earlier: Self) -> u32 {
79        self.duration_since(earlier).as_nanos() as u32
80    }
81}
82
83/// [`Interval`] implementation for `std`.
84#[derive(Clone)]
85pub struct StdInterval {
86    duration: Duration,
87}
88
89impl StdInterval {
90    /// - `duration`: the action in `interval()`.
91    ///     - `Duration::ZERO`: call `yield_now()`
92    ///     - `Duration`: call `sleep(duration)`
93    pub fn new(duration: Duration) -> Self {
94        Self { duration }
95    }
96}
97
98impl Interval for StdInterval {
99    #[inline]
100    fn interval(&self) {
101        match self.duration {
102            Duration::ZERO => yield_now(),
103            duration => sleep(duration),
104        }
105    }
106}
107
108#[cfg(test)]
109mod tests {
110    use super::*;
111
112    #[test]
113    fn std_waiter() {
114        let w = StdWaiter::new(Duration::from_millis(200), NonInterval::new());
115        let mut t = w.start();
116        assert!(!t.timeout());
117        sleep(Duration::from_millis(20));
118        assert!(!t.timeout());
119        sleep(Duration::from_millis(180));
120        assert!(t.timeout());
121        assert!(t.timeout());
122
123        let w = StdWaiter::new(
124            Duration::from_millis(500),
125            StdInterval::new(Duration::from_millis(260)),
126        );
127        let mut t = w.start();
128        assert!(!t.timeout());
129        assert!(!t.timeout());
130        assert!(t.timeout());
131        assert!(t.timeout());
132
133        t.restart();
134        assert!(!t.timeout());
135        assert!(!t.timeout());
136        assert!(t.timeout());
137        assert!(t.timeout());
138    }
139}