waiter_trait/
lib.rs

1//! Traits used to wait and timeout in a `no-std` embedded system.
2//!
3//! # Features
4//!
5//!- `std`: Disabled by default.
6//!
7//! # Usage
8//!
9//! 1. New a [`Waiter`] or [`TimedWaiter`] implementation.
10//! 2. Call `start()` to get a [`WaiterStatus`] implementation.
11//! 3. Call [`timeout()`](WaiterStatus::timeout) to check if the time limit expires.
12//!     1. [`Interval::interval`] is usually called in [`timeout()`](WaiterStatus::timeout)
13//!        before the time limit expires. It also depends on your implementation.
14//! 4. Call [`restart()`](WaiterStatus::restart) to reset the timeout condition if necessary.
15//!
16//! ## Example
17//!
18//! ```
19//! use waiter_trait::prelude::*;
20//!
21//! fn foo(waiter: impl Waiter) {
22//!     let mut t = waiter.start();
23//!     loop {
24//!         // Wait for something.
25//!
26//!         // Reset if it's necessary.
27//!         t.restart();
28//!
29//!         if t.timeout() {
30//!             break;
31//!         }
32//!     }
33//! }
34//! ```
35//!
36//! ## Pre-implemented
37//!
38//! - [`StdWaiter`] and [`StdInterval`]: Need the `std` feature enabled.
39//! - [`NonInterval`]: implements [`Interval`] that does nothing.
40//! - [`TickDelay`]: implements [`DelayNs`]
41//!
42//! # Implement Your Own
43//!
44//! For developers, you can choose one of the following options.
45//! - Implement [`Waiter`] or [`TimedWaiter`], and [`WaiterStatus`] then use them.
46//! - Implement [`TickInstant`] then use [`TickWaiter`] or [`TimedTickWaiter`].
47//!     - Simply give [`NonInterval`] to `Waiter`, If you don't need interval.
48//!       In this way, you can also use [`DelayNs`] or `sleep` separately.
49//!     - Or you can implement [`Interval`] and use it.
50//! - Using [`Counter`], if you don't have any tick source.
51
52#![cfg_attr(not(feature = "std"), no_std)]
53
54mod counter;
55pub use counter::*;
56mod non_interval;
57pub use non_interval::*;
58mod tick_waiter;
59pub use tick_waiter::*;
60mod tick_delay;
61pub use tick_delay::*;
62mod timed_tick_waiter;
63pub use timed_tick_waiter::*;
64
65#[cfg(feature = "std")]
66mod std_impls;
67#[cfg(feature = "std")]
68pub use std_impls::*;
69
70pub use embedded_hal::delay::DelayNs;
71pub use fugit::{self, MicrosDurationU32};
72
73pub mod prelude;
74
75pub trait Waiter {
76    /// Start waiting.
77    fn start(&self) -> impl WaiterStatus;
78}
79
80/// The difference from [`Waiter`] is that it supports setting timeout at `start()`.
81pub trait TimedWaiter {
82    /// Set timeout and start waiting.
83    fn start(&self, timeout: MicrosDurationU32) -> impl WaiterStatus;
84}
85
86pub trait WaiterStatus {
87    /// Check if the time limit expires. This function may sleeps for a while,
88    /// depends on the implementation.
89    fn timeout(&mut self) -> bool;
90    /// Reset the timeout condition.
91    fn restart(&mut self);
92}
93
94pub trait TickInstant: Copy {
95    fn now() -> Self;
96    /// Returns the amount of ticks elapsed from another instant to this one.
97    fn tick_since(self, earlier: Self) -> u32;
98    /// Returns the amount of ticks elapsed since this instant.
99    fn tick_elapsed(self) -> u32 {
100        Self::now().tick_since(self)
101    }
102}
103
104/// It is usually called at [`WaiterStatus::timeout`] before the time limit expires.
105/// It can be implemented for `yield`, `sleep` or do nothing.
106pub trait Interval: Clone {
107    fn interval(&self);
108}