aboutsummaryrefslogtreecommitdiff
path: root/embassy-executor/src/time/timer.rs
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2022-08-17 23:40:16 +0200
committerDario Nieuwenhuis <[email protected]>2022-08-18 01:22:30 +0200
commit5daa173ce4b153a532b4daa9e94c7a248231f25b (patch)
tree2ef0b4d6f9b1c02dac2589e7b57982c20cbc0e66 /embassy-executor/src/time/timer.rs
parent1c5b54a4823d596db730eb476c3ab78110557214 (diff)
Split embassy-time from embassy-executor.
Diffstat (limited to 'embassy-executor/src/time/timer.rs')
-rw-r--r--embassy-executor/src/time/timer.rs151
1 files changed, 0 insertions, 151 deletions
diff --git a/embassy-executor/src/time/timer.rs b/embassy-executor/src/time/timer.rs
deleted file mode 100644
index b9cdb1be5..000000000
--- a/embassy-executor/src/time/timer.rs
+++ /dev/null
@@ -1,151 +0,0 @@
1use core::future::Future;
2use core::pin::Pin;
3use core::task::{Context, Poll};
4
5use futures_util::future::{select, Either};
6use futures_util::{pin_mut, Stream};
7
8use crate::executor::raw;
9use crate::time::{Duration, Instant};
10
11/// Error returned by [`with_timeout`] on timeout.
12#[derive(Debug, Clone, PartialEq, Eq)]
13#[cfg_attr(feature = "defmt", derive(defmt::Format))]
14pub struct TimeoutError;
15
16/// Runs a given future with a timeout.
17///
18/// If the future completes before the timeout, its output is returned. Otherwise, on timeout,
19/// work on the future is stopped (`poll` is no longer called), the future is dropped and `Err(TimeoutError)` is returned.
20pub async fn with_timeout<F: Future>(timeout: Duration, fut: F) -> Result<F::Output, TimeoutError> {
21 let timeout_fut = Timer::after(timeout);
22 pin_mut!(fut);
23 match select(fut, timeout_fut).await {
24 Either::Left((r, _)) => Ok(r),
25 Either::Right(_) => Err(TimeoutError),
26 }
27}
28
29/// A future that completes at a specified [Instant](struct.Instant.html).
30pub struct Timer {
31 expires_at: Instant,
32 yielded_once: bool,
33}
34
35impl Timer {
36 /// Expire at specified [Instant](struct.Instant.html)
37 pub fn at(expires_at: Instant) -> Self {
38 Self {
39 expires_at,
40 yielded_once: false,
41 }
42 }
43
44 /// Expire after specified [Duration](struct.Duration.html).
45 /// This can be used as a `sleep` abstraction.
46 ///
47 /// Example:
48 /// ``` no_run
49 /// # #![feature(type_alias_impl_trait)]
50 /// #
51 /// # fn foo() {}
52 /// use embassy_executor::time::{Duration, Timer};
53 ///
54 /// #[embassy_executor::task]
55 /// async fn demo_sleep_seconds() {
56 /// // suspend this task for one second.
57 /// Timer::after(Duration::from_secs(1)).await;
58 /// }
59 /// ```
60 pub fn after(duration: Duration) -> Self {
61 Self {
62 expires_at: Instant::now() + duration,
63 yielded_once: false,
64 }
65 }
66}
67
68impl Unpin for Timer {}
69
70impl Future for Timer {
71 type Output = ();
72 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
73 if self.yielded_once && self.expires_at <= Instant::now() {
74 Poll::Ready(())
75 } else {
76 unsafe { raw::register_timer(self.expires_at, cx.waker()) };
77 self.yielded_once = true;
78 Poll::Pending
79 }
80 }
81}
82
83/// Asynchronous stream that yields every Duration, indefinitely.
84///
85/// This stream will tick at uniform intervals, even if blocking work is performed between ticks.
86///
87/// For instance, consider the following code fragment.
88/// ``` no_run
89/// # #![feature(type_alias_impl_trait)]
90/// #
91/// use embassy_executor::time::{Duration, Timer};
92/// # fn foo() {}
93///
94/// #[embassy_executor::task]
95/// async fn ticker_example_0() {
96/// loop {
97/// foo();
98/// Timer::after(Duration::from_secs(1)).await;
99/// }
100/// }
101/// ```
102///
103/// This fragment will not call `foo` every second.
104/// Instead, it will call it every second + the time it took to previously call `foo`.
105///
106/// Example using ticker, which will consistently call `foo` once a second.
107///
108/// ``` no_run
109/// # #![feature(type_alias_impl_trait)]
110/// #
111/// use embassy_executor::time::{Duration, Ticker};
112/// use futures::StreamExt;
113/// # fn foo(){}
114///
115/// #[embassy_executor::task]
116/// async fn ticker_example_1() {
117/// let mut ticker = Ticker::every(Duration::from_secs(1));
118/// loop {
119/// foo();
120/// ticker.next().await;
121/// }
122/// }
123/// ```
124pub struct Ticker {
125 expires_at: Instant,
126 duration: Duration,
127}
128
129impl Ticker {
130 /// Creates a new ticker that ticks at the specified duration interval.
131 pub fn every(duration: Duration) -> Self {
132 let expires_at = Instant::now() + duration;
133 Self { expires_at, duration }
134 }
135}
136
137impl Unpin for Ticker {}
138
139impl Stream for Ticker {
140 type Item = ();
141 fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
142 if self.expires_at <= Instant::now() {
143 let dur = self.duration;
144 self.expires_at += dur;
145 Poll::Ready(Some(()))
146 } else {
147 unsafe { raw::register_timer(self.expires_at, cx.waker()) };
148 Poll::Pending
149 }
150 }
151}