celox-runtime 0.4.1

Backend-independent Celox simulation runtime contracts
Documentation
use crate::{
    SignalRef,
    backend::{EventHandle, SimBackend},
};
use std::collections::BinaryHeap;

#[derive(Debug, Clone)]
pub struct ClockDef {
    pub period: u64,
}

#[derive(Debug, Clone)]
pub struct SimEvent<B: SimBackend> {
    pub time: u64,
    pub event_ref: B::Event,
    pub signal: SignalRef,
    pub next_val: u8,
}

impl<B: SimBackend> PartialEq for SimEvent<B> {
    fn eq(&self, other: &Self) -> bool {
        self.time == other.time
            && self.event_ref.addr() == other.event_ref.addr()
            && self.signal == other.signal
            && self.next_val == other.next_val
    }
}

impl<B: SimBackend> Eq for SimEvent<B> {}

impl<B: SimBackend> PartialOrd for SimEvent<B> {
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        Some(self.cmp(other))
    }
}

impl<B: SimBackend> Ord for SimEvent<B> {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        // Earlier time has higher priority (BinaryHeap is a Max-Heap)
        other
            .time
            .cmp(&self.time)
            .then_with(|| {
                let id1 = self.event_ref.id();
                let id2 = other.event_ref.id();
                id2.cmp(&id1)
            })
            .then_with(|| other.signal.cmp(&self.signal))
    }
}

pub struct Scheduler<B: SimBackend> {
    pub time: u64,
    pub clocks: Vec<Option<ClockDef>>,
    pub event_queue: BinaryHeap<SimEvent<B>>,
}

impl<B: SimBackend> Scheduler<B> {
    pub fn new() -> Self {
        Self {
            time: 0,
            clocks: Vec::new(),
            event_queue: BinaryHeap::new(),
        }
    }

    pub fn next_event_time(&self) -> Option<u64> {
        self.event_queue.peek().map(|e| e.time)
    }

    pub fn push(&mut self, event: SimEvent<B>) {
        self.event_queue.push(event);
    }

    pub fn pop_all_at_next_time(&mut self) -> Option<(u64, Vec<SimEvent<B>>)> {
        let next_time = self.next_event_time()?;
        let mut events = Vec::new();
        while let Some(ev) = self.event_queue.peek() {
            if ev.time == next_time {
                events.push(self.event_queue.pop().unwrap());
            } else {
                break;
            }
        }
        Some((next_time, events))
    }
}

impl<B: SimBackend> Default for Scheduler<B> {
    fn default() -> Self {
        Self::new()
    }
}