use core::fmt::{self, Debug};
use core::future::Future;
use core::pin::Pin;
use core::task::{Context, Poll, Waker};
use core::time::Duration;
use std::time::Instant;
pub struct Timer {
when: Option<Instant>,
period: Duration,
waker: Option<Waker>,
}
impl Timer {
pub fn never() -> Timer {
let _fix_linking = embassy_time::Timer::after(embassy_time::Duration::from_secs(1));
Timer {
when: None,
period: Duration::MAX,
waker: None,
}
}
pub fn after(duration: Duration) -> Timer {
let Some(start) = Instant::now().checked_add(duration) else {
return Timer::never();
};
Timer::interval_at(start, Duration::MAX)
}
pub fn at(instant: Instant) -> Timer {
Timer::interval_at(instant, Duration::MAX)
}
pub fn interval(period: Duration) -> Timer {
let Some(start) = Instant::now().checked_add(period) else {
return Timer::never();
};
Timer::interval_at(start, period)
}
pub fn interval_at(start: Instant, period: Duration) -> Timer {
if Self::ticks(&start).is_some() {
Timer {
when: Some(start),
period,
waker: None,
}
} else {
Timer::never()
}
}
#[inline]
pub fn will_fire(&self) -> bool {
self.when.is_some()
}
pub fn set_after(&mut self, duration: Duration) {
match Instant::now().checked_add(duration) {
Some(instant) => self.set_at(instant),
None => self.set_never(),
}
}
pub fn set_at(&mut self, instant: Instant) {
let ticks = Self::ticks(&instant);
if let Some(ticks) = ticks {
self.when = Some(instant);
self.period = Duration::MAX;
if let Some(waker) = self.waker.as_ref() {
embassy_time_driver::schedule_wake(ticks, waker);
}
} else {
self.set_never();
}
}
pub fn set_interval(&mut self, period: Duration) {
match Instant::now().checked_add(period) {
Some(instant) => self.set_interval_at(instant, period),
None => self.set_never(),
}
}
pub fn set_interval_at(&mut self, start: Instant, period: Duration) {
let ticks = Self::ticks(&start);
if let Some(ticks) = ticks {
self.when = Some(start);
self.period = period;
if let Some(waker) = self.waker.as_ref() {
embassy_time_driver::schedule_wake(ticks, waker);
}
} else {
self.set_never();
}
}
fn set_never(&mut self) {
self.when = None;
self.waker = None;
self.period = Duration::MAX;
}
fn fired_at(&mut self, cx: &mut Context<'_>) -> Option<Instant> {
let when = self.when?;
if when > Instant::now() {
let ticks = Self::ticks(&when);
if let Some(ticks) = ticks {
self.waker = Some(cx.waker().clone());
embassy_time_driver::schedule_wake(ticks, cx.waker());
} else {
self.set_never();
}
None
} else {
Some(when)
}
}
fn ticks(instant: &Instant) -> Option<u64> {
fn duration_ticks(duration: &Duration) -> Option<u64> {
let ticks = duration.as_secs() as u128 * embassy_time_driver::TICK_HZ as u128
+ duration.subsec_nanos() as u128 * embassy_time_driver::TICK_HZ as u128
/ 1_000_000_000;
u64::try_from(ticks).ok()
}
let now = Instant::now();
let now_ticks = embassy_time_driver::now();
if *instant >= now {
let dur_ticks = duration_ticks(&instant.duration_since(now));
dur_ticks.and_then(|dur_ticks| now_ticks.checked_add(dur_ticks))
} else {
let dur_ticks = duration_ticks(&now.duration_since(*instant));
dur_ticks.map(|dur_ticks| now_ticks.saturating_sub(dur_ticks))
}
}
}
impl Debug for Timer {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Timer")
.field("start", &self.when.as_ref())
.field("period", &self.period)
.finish()
}
}
impl Future for Timer {
type Output = Instant;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let Some(when) = self.fired_at(cx) else {
return Poll::Pending;
};
self.set_never();
Poll::Ready(when)
}
}
#[cfg(feature = "futures-lite")]
impl futures_lite::Stream for Timer {
type Item = Instant;
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
let Some(when) = self.fired_at(cx) else {
return Poll::Pending;
};
let next_when = when.checked_add(self.period);
if let Some(next_when) = next_when {
let period = self.period;
self.set_interval_at(next_when, period);
} else {
self.set_never();
}
Poll::Ready(Some(when))
}
}