omaha_client/
time.rs

1// Copyright 2020 The Fuchsia Authors
2//
3// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
4// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
5// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
6// This file may not be copied, modified, or distributed except according to
7// those terms.
8
9//! The `omaha_client::time` module provides a set of types and traits to allow for the expressing
10//! of time using both a wall-time clock, and a monotonic clock.
11//!
12//! The motivation for this is that wall-time is subject to being artibtrarily moved (forwards or
13//! backwards as the system's timekeeper decides is necessary), to keep it in sync with external
14//! systems.
15//!
16//! The monotonic clock, on the other hand, provides a consistently moving forward notion of time,
17//! but one that is not anchored at any particular external point in time.  It's epoch is therefore
18//! somewhat opaque by nature.  Rust's std::time::Instant takes this to the extreme of making the
19//! underlying value completely hidden from callers.
20//!
21//! One aspect of the `TimeSource` trait and the `ComplexTime` type is that they provide a way to
22//! pair the two timelines, and construct a time that is given in terms of each of these dimensions.
23//!
24//! What it doesn't try to do, is so that these pairings are the _same_ time.  They can be
25//! observations made concurrently (as in the case of `TimeSource::now() -> ComplexTime`),
26//! or they can be bounds for when an event in the future can happen:
27//!
28//! ```
29//! use omaha_client::time::{ComplexTime, MockTimeSource, TimeSource, Timer};
30//! use omaha_client::time::timers::MockTimer;
31//! use std::time::{Duration, SystemTime};
32//! let past_event_wall_time: SystemTime = SystemTime::now();
33//! let source = MockTimeSource::new_from_now();
34//! let duration_to_next = Duration::from_secs(1*60*60); // one hour
35//! let rough_next_event_time = ComplexTime{
36//!                               wall: past_event_wall_time + duration_to_next,
37//!                               mono: source.now_in_monotonic() + duration_to_next
38//!                             };
39//! let mut timer = MockTimer::new();
40//! timer.wait_until(rough_next_event_time);
41//! ```
42//!
43//! The above setups up a `ComplexTime` as a bound that based on an expected wall time, and
44//! monotonic time relative to `now`, such that the event can be described as "at time X, or within
45//! an hour" when used with `Timer::wait_until`, or "after time X, at least an hour from now", if
46//! used with `Timer::wait_until_all`.
47//!
48//! # Usage Guidelines
49//!
50//! The `ComplexTime` and `PartialComplexTime` structs give the ability to represent a number of
51//! states of knowledge about a time.
52//!
53//! When modeling the known time for something:
54//!
55//! * `ComplexTime` - When both wall and monotonic times are always known
56//! * `PartialComplexTime` - When some time (wall, monotonic, or both) is always known
57//! * `Option<ComplexTime> - When time is either known for both timelines, or not at all.
58//! * `Option<PartialComplexTime> - Situations where time can be in any of 4 states:
59//!   * None whatsoever
60//!   * Only wall time
61//!   * Only monotonic time
62//!   * Both are known
63//!
64//! When modeling the time required (e.g. timer waits):
65//! * `ComplexTime` - When both wall and monotonic times are always required
66//! * `PartialComplexTime` - When some time (wall, monotonic, or both) is always required, but any
67//!   or both will suffice.
68//!
69
70use chrono::{DateTime, Utc};
71use futures::future::BoxFuture;
72use std::{
73    fmt::{Debug, Display},
74    hash::Hash,
75    time::{Duration, Instant, SystemTime},
76};
77
78// NOTE:  Implementations for the main types of this module have been moved to inner modules that
79//        that are exposed via `pub use`, so that it's easier to read through the declarations of
80//        the main types and see how they are meant to be used together.  Implementations are in the
81//        same order as the declarations of the types.
82
83// Implementations and tests for `ComplexTime` and `PartialComplexTime`
84mod complex;
85pub use complex::system_time_conversion;
86
87/// This is a complete `ComplexTime`, which has values on both the wall clock timeline and the
88/// monotonic clock timeline.
89///
90/// It is not necessarily intended that both values refer to the same moment.  They can, or they
91/// can refer to a time on each clock's respective timeline, e.g. for use with the `Timer` trait.
92///
93/// The `ComplexTime` type implements all the standard math operations in `std::ops` that are
94/// implemented for both `std::time::SystemTime` and `std::time::Instant`.  Like those
95/// implementations, it will panic on overflow.
96#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
97pub struct ComplexTime {
98    pub wall: SystemTime,
99    pub mono: Instant,
100}
101impl ComplexTime {
102    /// Truncate the submicrosecond part of the walltime.
103    pub fn truncate_submicrosecond_walltime(&self) -> ComplexTime {
104        let nanos_in_one_micro = Duration::from_micros(1).as_nanos();
105        let submicrosecond_nanos = match self.wall_duration_since(SystemTime::UNIX_EPOCH) {
106            Ok(duration) => duration.as_nanos() % nanos_in_one_micro,
107            Err(e) => nanos_in_one_micro - e.duration().as_nanos() % nanos_in_one_micro,
108        };
109        ComplexTime {
110            wall: self.wall - Duration::from_nanos(submicrosecond_nanos as u64),
111            mono: self.mono,
112        }
113    }
114    /// Compute the Duration since the given SystemTime, for the SystemTime component of this
115    /// ComplexTime.  If this ComplexTime's SystemTime is before the given time, the Duration
116    /// is returned as Err (same as `SystemTime::duration_since()`)
117    pub fn wall_duration_since(
118        &self,
119        earlier: impl Into<SystemTime>,
120    ) -> Result<Duration, std::time::SystemTimeError> {
121        self.wall.duration_since(earlier.into())
122    }
123
124    /// Returns `true` if this ComplexTime is after either the SystemTime or the Instant of the
125    /// given PartialComplexTime.
126    pub fn is_after_or_eq_any(&self, other: impl Into<PartialComplexTime>) -> bool {
127        match other.into() {
128            PartialComplexTime::Wall(w) => self.wall >= w,
129            PartialComplexTime::Monotonic(m) => self.mono >= m,
130            PartialComplexTime::Complex(c) => self.wall >= c.wall || self.mono >= c.mono,
131        }
132    }
133}
134
135// Implementations for `Display`, `Add`, `AddAssign`, `Sub`, `SubAssign` are found in
136// `mod complex::complex_time_impls`
137//
138// Implementations for `From<>` are found in `mod complex::complex_time_type_conversions`
139
140/// `PartialComplexTime` holds a value for at least one timeline.
141///
142/// `PartialComplexTime` provides a `std::interator::EitherOrBoth`-like type which is specifically
143/// for holding either one, or both, of the time types that make up a `ComplexTime`.  It's a type
144/// that holds a value for at least one of the timelines.
145///
146/// The important differentiation of this vs. a struct such as:
147/// ```
148/// use std::time::SystemTime;
149/// struct MaybeBoth {
150///   wall: Option<SystemTime>,
151///   monotonic: Option<SystemTime>
152///}
153/// ```
154/// is that there is no valid `(None, None)` state for this type to be in, and so code that uses can
155/// be certain that _some_ time is specified.
156///
157/// Like `ComplexTime`, `PartialComplexTime` implements all the standard math operations in
158/// `std::ops` that are implemented for both `std::time::SystemTime` and  `std::time:Instant`.  Like
159/// those implementations, they will panic on overflow.
160#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
161pub enum PartialComplexTime {
162    /// Just a wall time.
163    Wall(SystemTime),
164    /// Just a monotonic time.
165    Monotonic(Instant),
166    /// Both a wall and a monotonic time.
167    Complex(ComplexTime),
168}
169impl PartialComplexTime {
170    /// Return the SystemTime component, if one exists.
171    pub fn checked_to_system_time(self) -> Option<SystemTime> {
172        self.destructure().0
173    }
174
175    /// Return the Instant component, if one exists.
176    pub fn checked_to_instant(self) -> Option<Instant> {
177        self.destructure().1
178    }
179
180    /// Convert the SystemTime component of this PartialComplexTime into i64 microseconds from
181    /// the UNIX Epoch.  Provides coverage over +/- approx 30,000 years from 1970-01-01 UTC.
182    ///
183    /// Returns None if it doesn't have a wall time or on overflow (instead of panicking)
184    pub fn checked_to_micros_since_epoch(self) -> Option<i64> {
185        self.checked_to_system_time()
186            .and_then(system_time_conversion::checked_system_time_to_micros_from_epoch)
187    }
188
189    /// Return the PartialComplexTime::Wall that represents the same time as the specified
190    /// microseconds from the UNIX Epoch (1970-01-01 UTC)
191    pub fn from_micros_since_epoch(micros: i64) -> Self {
192        PartialComplexTime::from(system_time_conversion::micros_from_epoch_to_system_time(
193            micros,
194        ))
195    }
196
197    /// Return a new ComplexTime that's based on the time values of this PartialComplexTime,
198    /// setting either unknown field from the passed-in ComplexTime.
199    pub fn complete_with(&self, complex: ComplexTime) -> ComplexTime {
200        let (system, instant) = self.destructure();
201        ComplexTime::from((
202            system.unwrap_or(complex.wall),
203            instant.unwrap_or(complex.mono),
204        ))
205    }
206
207    /// Destructure the PartialComplexTime into it's two components, each as an Option.
208    pub fn destructure(&self) -> (Option<SystemTime>, Option<Instant>) {
209        match *self {
210            PartialComplexTime::Wall(w) => (Some(w), None),
211            PartialComplexTime::Monotonic(m) => (None, Some(m)),
212            PartialComplexTime::Complex(c) => (Some(c.wall), Some(c.mono)),
213        }
214    }
215}
216
217// Implementations for `Display`, `Add`, `AddAssign`, `Sub`, `SubAssign` are found in
218// `mod complex::partial_complex_time_impls`
219//
220// Implementations for `From<>` are found in `mod complex::partial_complex_time_type_conversions`
221
222/// Trait for timers that understand how to work with the `ComplexTime` and `PartialComplexTime`
223/// types.
224///
225/// When using a `PartialComplexTime`, the trait defines Fns for waiting until any of the times have
226/// been reached, or until all of them have been reached.
227pub trait Timer {
228    /// Wait until at least one of the given time bounds has been reached.
229    fn wait_until(&mut self, time: impl Into<PartialComplexTime>) -> BoxFuture<'static, ()>;
230
231    /// Wait for the given duration (from now).
232    fn wait_for(&mut self, duration: Duration) -> BoxFuture<'static, ()>;
233}
234// Implementations and tests for test `Timers`.  Not marked as #[cfg(test)] to allow use in tests
235// in crates that use this.
236pub mod timers;
237
238/// `TimeSource` is a trait for providing access to both the "System" (aka "Wall") time for
239/// platform, as well as its monotonic time.
240pub trait TimeSource {
241    /// Returns the current wall time.
242    fn now_in_walltime(&self) -> SystemTime;
243
244    /// Returns the current montonic time.
245    fn now_in_monotonic(&self) -> Instant;
246
247    /// Returns the current ComplexTime (both wall and monotonic times).
248    fn now(&self) -> ComplexTime;
249}
250
251// Implementations and tests for `TimeSource`
252pub mod time_source;
253pub use time_source::MockTimeSource;
254pub use time_source::StandardTimeSource;
255
256impl<T> TimeSource for &T
257where
258    T: TimeSource,
259{
260    fn now_in_walltime(&self) -> SystemTime {
261        (*self).now_in_walltime()
262    }
263    fn now_in_monotonic(&self) -> Instant {
264        (*self).now_in_monotonic()
265    }
266    fn now(&self) -> ComplexTime {
267        (*self).now()
268    }
269}
270
271/// Helper struct for providing a consistent, readable `SystemTime`.
272///
273/// This displays a `SystemTime` in a human-readable date+time in UTC plus the raw `[seconds].[ns]`
274/// since epoch of the SystemTime.
275///
276/// # Example
277/// ```
278/// use omaha_client::time::ReadableSystemTime;
279/// use std::time::{Duration, SystemTime};
280/// let sys_time = SystemTime::UNIX_EPOCH + Duration::from_nanos(994610096026420000);
281///
282/// assert_eq!(
283///     format!("{}", ReadableSystemTime(sys_time)),
284///     "2001-07-08 16:34:56.026 UTC (994610096.026420000)"
285/// );
286/// ```
287pub struct ReadableSystemTime(pub SystemTime);
288impl Display for ReadableSystemTime {
289    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
290        let format = DateTime::<Utc>::from(self.0).format("%Y-%m-%d %H:%M:%S%.3f %Z (%s%.9f)");
291        Display::fmt(&format, f)
292    }
293}
294impl Debug for ReadableSystemTime {
295    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
296        Display::fmt(self, f)
297    }
298}
299
300#[cfg(test)]
301mod tests_for_readable_system_time {
302    use super::*;
303
304    #[test]
305    fn test_readable_system_time() {
306        let sys_time = SystemTime::UNIX_EPOCH + Duration::from_nanos(994610096026420000);
307
308        assert_eq!(
309            format!("{}", ReadableSystemTime(sys_time)),
310            "2001-07-08 16:34:56.026 UTC (994610096.026420000)"
311        );
312    }
313}