embedded-timers 0.4.0

Softwaretimers and -delays (ms/us) based on a Clock implementation
Documentation
// Copyright Open Logistics Foundation
//
// Licensed under the Open Logistics Foundation License 1.3.
// For details on the licensing terms, see the LICENSE file.
// SPDX-License-Identifier: OLFL-1.3

use core::time::Duration;

use crate::instant::Instant;

/// Clock trait for clocks which are expected to be always running and never fail
///
/// The trait has an associated type `Instant` which needs to implement the [`Instant`] trait. For
/// most users of this trait, it should be fine to keep this type generic and not further restrict
/// it. This will keep the code compatible with all clock implementations and improve
/// platform-independence. If a specific type is required for whatever reason, the
/// [`instant`](crate::instant) module defines some types which could be used by clock
/// implementers. Keep in mind though, that even if the `Instant` type would support
/// high-resolution clocks, this does not guarantee that the underlying clock actually supports
/// that resolution. Therefore, clock resolution requirements need to be documented in a different
/// way.
///
/// The design decision to define the clock trait as infallible has been made because handling
/// clock errors is often extremely difficult. Experience has shown that clock users tend to
/// `unwrap` on all clock interactions, if not directly then at least eventually after propagating
/// errors as far as they could. Having an infallible clock trait is cleaner because it
/// communicates that clock implementers need to make sure that the clock is always working, at
/// least for the time it is available to the clock users. If, for some reason, working with a
/// fallible clock is required, an approach might be to use a (properly synchronized) global
/// `Option<&impl Clock>` which is set to `None` whenever the clock is not available. But this use
/// case is explicitly not supported or advocated for by this crate.
///
/// Since the [`Instant`] trait could not contain the
/// [`std::time::Instant::elapsed`](https://doc.rust-lang.org/stable/std/time/struct.Instant.html#method.elapsed)
/// method which depends on a global clock, this method is moved here in addition to the
/// [`now`](Clock::now) method.
///
/// All methods in this trait require shared `&` references so that a single clock reference can be
/// shared and used for a whole application. This might be in contrast to many embedded approaches
/// in which such hardware-related accesses are often done via an exclusive `&mut` reference. But in
/// fact, this trait is not designed to describe exclusive access to a hardware clock (with the
/// possibility to start, stop or reconfigure it), but to gain access to a virtually global shared
/// clock. To allow this, clock implementers need to use an effective synchronization or locking
/// mechanism to allow such accesses.
pub trait Clock {
    /// Associated instant type which is returned from the `now` method
    type Instant: Instant;

    /// Returns the current time as an instant
    fn now(&self) -> Self::Instant;

    /// Returns the amount of time elapsed since the given instant.
    ///
    /// # Panics
    ///
    /// As in the current version of the Rust stdlib, this method saturates instead of panicking.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// use core::time::Duration;
    /// use embedded_timers::instant::Instant;
    /// use embedded_timers::clock::Clock;
    /// # use embedded_timers::instant::Instant32;
    /// # fn sleep(_duration: Duration) {}
    /// # struct MyClock;
    /// # impl embedded_timers::clock::Clock for MyClock {
    /// #     type Instant = Instant32<1000>;
    /// #     fn now(&self) -> Instant32<1000> {
    /// #         Instant32::new(0)
    /// #     }
    /// # }
    ///
    /// let clock = MyClock;
    /// let instant = clock.now();
    /// let three_secs = Duration::from_secs(3);
    /// sleep(three_secs);
    /// assert!(clock.elapsed(instant) >= three_secs);
    /// ```
    #[must_use]
    fn elapsed(&self, instant: Self::Instant) -> Duration {
        self.now().duration_since(instant)
    }
}