use std::cell::{Cell, RefCell};
use std::cmp::Ordering;
use std::collections::BinaryHeap;
use std::time::{Duration, Instant};
use crate::EventId;
use crate::Reactor;
use crate::TemporalReactor;
#[derive(Copy, Clone)]
pub enum SleepMode {
Actual, Emulated, }
pub struct ToyReactor {
rimpl: RefCell<ToyReactorImpl>,
}
impl ToyReactor {
pub fn new() -> Self {
Self::new_with_mode(SleepMode::Actual)
}
pub fn new_with_mode(mode: SleepMode) -> Self {
ToyReactor {
rimpl: RefCell::new(ToyReactorImpl::new(mode)),
}
}
pub fn now32(&self) -> u32 {
self.rimpl.borrow_mut().now32()
}
}
impl Reactor for ToyReactor {
fn wait(&self) -> EventId {
self.rimpl.borrow_mut().wait()
}
}
impl TemporalReactor for ToyReactor {
fn schedule_timer(&self, event_id: EventId, duration: Duration) {
self.rimpl
.borrow_mut()
.schedule_timer(event_id, duration);
}
fn cancel_timer(&self, event_id: EventId) {
self.rimpl.borrow_mut().cancel_timer(event_id);
}
}
struct TimerNode {
wake_on: u32,
event_id: EventId,
cancelled: Cell<bool>,
}
impl TimerNode {
fn new(now32: u32, duration: Duration, event_id: EventId) -> Self {
TimerNode {
wake_on: now32 + Self::get_duration_u32(duration),
event_id,
cancelled: Cell::new(false),
}
}
fn cancel(&self) {
self.cancelled.set(true);
}
fn get_duration_u32(duration: Duration) -> u32 {
let duration: u128 = duration.as_millis();
assert!(
duration <= ToyReactor::MAX_TIMER_DURATION_MS as u128,
"aiur: Sleep duration is too big: {}ms (max is {}ms)",
duration,
ToyReactor::MAX_TIMER_DURATION_MS
);
duration as u32
}
}
impl PartialOrd for TimerNode {
fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
Some(self.wake_on.cmp(&rhs.wake_on).reverse())
}
}
impl PartialEq for TimerNode {
fn eq(&self, rhs: &Self) -> bool {
self.wake_on == rhs.wake_on
}
}
impl Eq for TimerNode {}
impl Ord for TimerNode {
fn cmp(&self, rhs: &Self) -> Ordering {
self.partial_cmp(rhs).unwrap()
}
}
enum SleepModeImpl {
Actual { system_now32_origin: Instant },
Emulated { emulated_now32: u32 },
}
impl SleepModeImpl {
fn now32(&self) -> u32 {
match self {
SleepModeImpl::Actual {
system_now32_origin,
} => system_now32_origin.elapsed().as_millis() as u32,
SleepModeImpl::Emulated { emulated_now32 } => *emulated_now32,
}
}
fn sleep(&mut self, ms: u32) {
match self {
SleepModeImpl::Actual { .. } => Self::actual_sleep(ms),
SleepModeImpl::Emulated { emulated_now32 } => Self::emulated_sleep(emulated_now32, ms),
}
}
fn emulated_sleep(emulated_now32: &mut u32, ms: u32) {
*emulated_now32 += ms;
}
fn actual_sleep(ms: u32) {
std::thread::sleep(Duration::from_millis(ms as u64));
}
}
impl From<SleepMode> for SleepModeImpl {
fn from(sleep_mode: SleepMode) -> Self {
match sleep_mode {
SleepMode::Actual => SleepModeImpl::Actual {
system_now32_origin: Instant::now(),
},
SleepMode::Emulated => SleepModeImpl::Emulated { emulated_now32: 0 },
}
}
}
struct ToyReactorImpl {
timers: BinaryHeap<TimerNode>,
sleep_mode: SleepModeImpl,
}
impl ToyReactorImpl {
fn new(sleep_mode: SleepMode) -> Self {
ToyReactorImpl {
timers: BinaryHeap::new(),
sleep_mode: SleepModeImpl::from(sleep_mode),
}
}
fn schedule_timer(&mut self, event_id: EventId, duration: Duration) {
println!("schedule_timer: {:?}", event_id);
self.timers
.push(TimerNode::new(self.now32(), duration, event_id));
}
fn cancel_timer(&mut self, event_id: EventId) {
println!("cancel_timer: {:?}", event_id);
self.timers
.iter()
.find(|x| {
println!("{:?}", x.event_id);
x.event_id == event_id
})
.expect("Attempt to remove unknown timer")
.cancel();
}
fn now32(&self) -> u32 {
self.sleep_mode.now32()
}
fn get_first_timer_to_wake(&mut self) -> TimerNode {
loop {
let timer_node = self
.timers
.pop()
.expect(concat!(
"aiur: ToyReactor::wait() invoked with nothing to wait. ",
"It looks like some kind a bug in aiur::Runtime that it invoked wait(), ",
"knowing that there is nothing to wait."
));
if !timer_node.cancelled.get() {
return timer_node;
}
}
}
fn wait(&mut self) -> EventId {
println!("toy reactor wait");
let timer_node = self.get_first_timer_to_wake();
let now32 = self.now32();
if timer_node.wake_on > now32 {
self.sleep_mode.sleep(timer_node.wake_on - now32);
}
timer_node.event_id
}
}