omaha_client_fuchsia/
timer.rs

1// Copyright 2019 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use fuchsia_async as fasync;
6use futures::future::BoxFuture;
7use futures::prelude::*;
8use omaha_client::time::{PartialComplexTime, Timer};
9use std::cmp::min;
10use std::time::{Duration, Instant, SystemTime};
11
12pub struct FuchsiaTimer;
13impl FuchsiaTimer {
14    // Return the duration until the given SystemTime, or a 0-length duration if it's in the past.
15    // w.r.t clippy, Duration::from_secs is a const fn, and is more readable than unwrap_or_default
16    #[allow(clippy::or_fun_call)]
17    fn duration_until_system_time(system: SystemTime) -> Duration {
18        system.duration_since(SystemTime::now()).ok().unwrap_or(Duration::from_secs(0))
19    }
20
21    // Return the duration until the given Instant, or a 0-length duration if it's in the past.
22    // w.r.t clippy, Duration::from_secs is a const fn, and is more readable than unwrap_or_default
23    #[allow(clippy::or_fun_call)]
24    fn duration_until_instant(instant: Instant) -> Duration {
25        instant.checked_duration_since(Instant::now()).unwrap_or(Duration::from_secs(0))
26    }
27
28    fn determine_wait_until(time: PartialComplexTime) -> Duration {
29        match time {
30            PartialComplexTime::Wall(w) => Self::duration_until_system_time(w),
31            PartialComplexTime::Monotonic(m) => Self::duration_until_instant(m),
32            PartialComplexTime::Complex(c) => {
33                min(Self::duration_until_system_time(c.wall), Self::duration_until_instant(c.mono))
34            }
35        }
36    }
37}
38impl Timer for FuchsiaTimer {
39    /// Wait until at least one of the given time bounds has been reached.
40    fn wait_until(&mut self, time: impl Into<PartialComplexTime>) -> BoxFuture<'static, ()> {
41        fasync::Timer::new(Self::determine_wait_until(time.into())).boxed()
42    }
43
44    /// Wait for the given duration (from now).
45    fn wait_for(&mut self, duration: Duration) -> BoxFuture<'static, ()> {
46        fasync::Timer::new(duration).boxed()
47    }
48}
49
50#[cfg(test)]
51mod tests {
52    use super::*;
53    use fuchsia_async::TestExecutor;
54    use std::task::Poll;
55
56    #[fuchsia::test(allow_stalls = false)]
57    async fn test_timer() {
58        let start_time = fasync::MonotonicInstant::now();
59
60        let mut timer = FuchsiaTimer;
61        let mut future = timer.wait_for(Duration::from_secs(1234));
62        assert_eq!(Poll::Pending, TestExecutor::poll_until_stalled(&mut future).await);
63
64        let future_time = TestExecutor::next_timer().unwrap();
65        TestExecutor::advance_to(future_time).await;
66        assert_eq!(1234, (future_time - start_time).into_seconds());
67
68        let () = future.await;
69    }
70}