use std::cell::RefCell;
use std::cmp::Ordering;
use std::future::Future;
use std::pin::Pin;
use std::rc::Rc;
use std::task::{Context, Poll, Waker};
use crate::{state::SimulationState, Id};
pub(crate) type TimerId = u64;
pub struct TimerFuture {
timer_id: TimerId,
state: Rc<RefCell<TimerAwaitState>>,
sim_state: Rc<RefCell<SimulationState>>,
}
impl TimerFuture {
fn new(timer_id: TimerId, state: Rc<RefCell<TimerAwaitState>>, sim_state: Rc<RefCell<SimulationState>>) -> Self {
Self {
timer_id,
state,
sim_state,
}
}
}
impl Future for TimerFuture {
type Output = ();
fn poll(self: Pin<&mut Self>, async_ctx: &mut Context) -> Poll<Self::Output> {
let mut state = self.state.as_ref().borrow_mut();
if state.completed {
Poll::Ready(())
} else {
state.waker = Some(async_ctx.waker().clone());
Poll::Pending
}
}
}
impl Drop for TimerFuture {
fn drop(&mut self) {
if !self.state.borrow().completed && !self.state.borrow().manually_dropped {
self.sim_state
.borrow_mut()
.on_incomplete_timer_future_drop(self.timer_id);
}
}
}
#[derive(Clone)]
pub(crate) struct TimerPromise {
pub id: TimerId,
pub component_id: Id,
pub time: f64,
state: Rc<RefCell<TimerAwaitState>>,
}
impl TimerPromise {
pub(crate) fn new(id: TimerId, component_id: Id, time: f64) -> Self {
Self {
id,
component_id,
time,
state: Rc::new(RefCell::new(TimerAwaitState::new())),
}
}
pub fn future(&self, sim_state: Rc<RefCell<SimulationState>>) -> TimerFuture {
TimerFuture::new(self.id, self.state.clone(), sim_state)
}
pub fn complete(&self) {
self.state.borrow_mut().complete();
}
pub fn drop_state(&self) {
let _waker = self.state.borrow_mut().drop();
}
}
impl Eq for TimerPromise {}
impl PartialEq for TimerPromise {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
}
}
impl Ord for TimerPromise {
fn cmp(&self, other: &Self) -> Ordering {
other.time.total_cmp(&self.time).then_with(|| other.id.cmp(&self.id))
}
}
impl PartialOrd for TimerPromise {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
struct TimerAwaitState {
pub completed: bool,
pub manually_dropped: bool,
pub waker: Option<Waker>,
}
impl TimerAwaitState {
pub fn new() -> Self {
Self {
completed: false,
manually_dropped: false,
waker: None,
}
}
pub fn complete(&mut self) {
self.completed = true;
if let Some(waker) = self.waker.take() {
waker.wake();
}
}
pub fn drop(&mut self) -> Option<Waker> {
self.manually_dropped = true;
self.waker.take()
}
}