embedded_timers/clock.rs
1// Copyright Open Logistics Foundation
2//
3// Licensed under the Open Logistics Foundation License 1.3.
4// For details on the licensing terms, see the LICENSE file.
5// SPDX-License-Identifier: OLFL-1.3
6
7use core::time::Duration;
8
9use crate::instant::Instant;
10
11/// Clock trait for clocks which are expected to be always running and never fail
12///
13/// The trait has an associated type `Instant` which needs to implement the [`Instant`] trait. For
14/// most users of this trait, it should be fine to keep this type generic and not further restrict
15/// it. This will keep the code compatible with all clock implementations and improve
16/// platform-independence. If a specific type is required for whatever reason, the
17/// [`instant`](crate::instant) module defines some types which could be used by clock
18/// implementers. Keep in mind though, that even if the `Instant` type would support
19/// high-resolution clocks, this does not guarantee that the underlying clock actually supports
20/// that resolution. Therefore, clock resolution requirements need to be documented in a different
21/// way.
22///
23/// The design decision to define the clock trait as infallible has been made because handling
24/// clock errors is often extremely difficult. Experience has shown that clock users tend to
25/// `unwrap` on all clock interactions, if not directly then at least eventually after propagating
26/// errors as far as they could. Having an infallible clock trait is cleaner because it
27/// communicates that clock implementers need to make sure that the clock is always working, at
28/// least for the time it is available to the clock users. If, for some reason, working with a
29/// fallible clock is required, an approach might be to use a (properly synchronized) global
30/// `Option<&impl Clock>` which is set to `None` whenever the clock is not available. But this use
31/// case is explicitly not supported or advocated for by this crate.
32///
33/// Since the [`Instant`] trait could not contain the
34/// [`std::time::Instant::elapsed`](https://doc.rust-lang.org/stable/std/time/struct.Instant.html#method.elapsed)
35/// method which depends on a global clock, this method is moved here in addition to the
36/// [`now`](Clock::now) method.
37///
38/// All methods in this trait require shared `&` references so that a single clock reference can be
39/// shared and used for a whole application. This might be in contrast to many embedded approaches
40/// in which such hardware-related accesses are often done via an exclusive `&mut` reference. But in
41/// fact, this trait is not designed to describe exclusive access to a hardware clock (with the
42/// possibility to start, stop or reconfigure it), but to gain access to a virtually global shared
43/// clock. To allow this, clock implementers need to use an effective synchronization or locking
44/// mechanism to allow such accesses.
45pub trait Clock {
46 /// Associated instant type which is returned from the `now` method
47 type Instant: Instant;
48
49 /// Returns the current time as an instant
50 fn now(&self) -> Self::Instant;
51
52 /// Returns the amount of time elapsed since the given instant.
53 ///
54 /// # Panics
55 ///
56 /// As in the current version of the Rust stdlib, this method saturates instead of panicking.
57 ///
58 /// # Examples
59 ///
60 /// ```no_run
61 /// use core::time::Duration;
62 /// use embedded_timers::instant::Instant;
63 /// use embedded_timers::clock::Clock;
64 /// # use embedded_timers::instant::Instant32;
65 /// # fn sleep(_duration: Duration) {}
66 /// # struct MyClock;
67 /// # impl embedded_timers::clock::Clock for MyClock {
68 /// # type Instant = Instant32<1000>;
69 /// # fn now(&self) -> Instant32<1000> {
70 /// # Instant32::new(0)
71 /// # }
72 /// # }
73 ///
74 /// let clock = MyClock;
75 /// let instant = clock.now();
76 /// let three_secs = Duration::from_secs(3);
77 /// sleep(three_secs);
78 /// assert!(clock.elapsed(instant) >= three_secs);
79 /// ```
80 #[must_use]
81 fn elapsed(&self, instant: Self::Instant) -> Duration {
82 self.now().duration_since(instant)
83 }
84}