use alloc::rc::Rc;
use core::cell::{Cell, RefCell};
use core::fmt;
use core::future::Future;
use core::pin::Pin;
use core::time::Duration;
use futures_util::future::FutureExt;
use futures_util::pin_mut;
use futures_util::stream::Stream;
use futures_util::task::{AtomicWaker, Context, Poll};
use ndless::alloc::fmt::Formatter;
use ndless::prelude::*;
use ndless::timer::{configure_sleep, get_ticks, has_time_passed, Ticks, TICKS_PER_SECOND};
use crate::select;
struct TimerData {
at_tick: Cell<u32>,
waker: AtomicWaker,
}
#[derive(Default)]
pub struct TimerListener {
timers: RefCell<Vec<Rc<TimerData>>>,
}
impl TimerListener {
pub(crate) fn poll(&self) {
let mut timers = self.timers.borrow_mut();
timers.retain(|timer| Rc::strong_count(timer) > 1);
timers.iter().for_each(|timer| {
if has_time_passed(timer.at_tick.get()) {
timer.waker.wake();
}
})
}
pub(crate) fn config_sleep(&self) {
let half_max = 2u32.pow(31);
let mut timers = self.timers.borrow_mut();
timers.retain(|timer| Rc::strong_count(timer) > 1);
if let Some(time) = timers
.iter()
.map(|timer| timer.at_tick.get().wrapping_sub(get_ticks()) % half_max)
.min()
{
configure_sleep(time);
}
}
pub fn sleep_ms(&self, ms: u32) -> Timer {
self.sleep(Duration::from_millis(ms as u64))
}
pub fn sleep(&self, dur: Duration) -> Timer {
self.sleep_ticks(dur.as_ticks())
}
pub fn sleep_ticks(&self, ticks: u32) -> Timer {
self.sleep_until(get_ticks().wrapping_add(ticks))
}
pub fn sleep_until(&self, ticks: u32) -> Timer {
let timer = Rc::new(TimerData {
at_tick: Cell::new(ticks),
waker: AtomicWaker::new(),
});
let mut timers = self.timers.borrow_mut();
timers.push(timer.clone());
Timer(timer)
}
pub async fn timeout_ms<T>(
&self,
ms: u32,
f: impl Future<Output = T>,
) -> Result<T, TimeoutError> {
self.timeout(Duration::from_millis(ms as u64), f).await
}
pub async fn timeout<T>(
&self,
dur: Duration,
f: impl Future<Output = T>,
) -> Result<T, TimeoutError> {
self.timeout_ticks(dur.as_ticks(), f).await
}
pub async fn timeout_ticks<T>(
&self,
ticks: u32,
f: impl Future<Output = T>,
) -> Result<T, TimeoutError> {
self.timeout_until(get_ticks().wrapping_add(ticks), f).await
}
pub async fn timeout_until<T>(
&self,
ticks: u32,
f: impl Future<Output = T>,
) -> Result<T, TimeoutError> {
let f = f.fuse();
pin_mut!(f);
select! {
x = f => Ok(x),
_ = self.sleep_until(ticks).fuse() => Err(TimeoutError),
}
}
pub fn every_hz(&self, hz: u32) -> Interval {
self.every_ticks(TICKS_PER_SECOND / hz)
}
pub fn every_ms(&self, ms: u32) -> Interval {
self.every(Duration::from_millis(ms as u64))
}
pub fn every(&self, dur: Duration) -> Interval {
self.every_ticks(dur.as_ticks())
}
pub fn every_ticks(&self, ticks: u32) -> Interval {
Interval {
interval: ticks,
timer: self.sleep_ticks(ticks),
}
}
}
pub struct Interval {
interval: u32,
timer: Timer,
}
impl Interval {
pub fn interval(&self) -> Duration {
Duration::from_ticks(self.interval)
}
pub fn interval_ms(&self) -> u32 {
self.interval().as_ticks()
}
pub fn interval_ticks(&self) -> u32 {
self.interval
}
pub fn reschedule_ms(&mut self, ms: u32) {
self.reschedule(Duration::from_millis(ms as u64))
}
pub fn reschedule(&mut self, dur: Duration) {
self.reschedule_ticks(dur.as_ticks())
}
pub fn reschedule_ticks(&mut self, ticks: u32) {
self.interval = ticks;
self.timer.reschedule_ticks(ticks)
}
}
impl Stream for Interval {
type Item = Duration;
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
let res = Pin::new(&mut self.timer).poll(cx);
match res {
Poll::Ready(dur) => {
self.timer.reschedule_ticks(self.interval);
Poll::Ready(Some(dur))
}
Poll::Pending => Poll::Pending,
}
}
}
pub struct Timer(Rc<TimerData>);
impl Timer {
pub fn at_tick(&self) -> u32 {
self.0.at_tick.get()
}
pub fn reschedule_ms(&self, ms: u32) {
self.reschedule(Duration::from_millis(ms as u64))
}
pub fn reschedule(&self, dur: Duration) {
self.reschedule_ticks(dur.as_ticks())
}
pub fn reschedule_ticks(&self, ticks: u32) {
self.reschedule_at(get_ticks().wrapping_add(ticks))
}
pub fn reschedule_at(&self, ticks: u32) {
self.0.at_tick.set(ticks);
}
}
impl Future for Timer {
type Output = Duration;
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
let at_tick = self.at_tick();
if has_time_passed(at_tick) {
Poll::Ready(Duration::from_ticks(get_ticks().wrapping_sub(at_tick)))
} else {
self.0.waker.register(cx.waker());
Poll::Pending
}
}
}
#[derive(Eq, PartialEq, Copy, Clone, Default, Debug, Hash)]
pub struct TimeoutError;
impl fmt::Display for TimeoutError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
"future has timed out".fmt(f)
}
}