use std::num::NonZeroU64;
use awint::awint_dag::triple_arena::{OrdArena, Recast, Recaster};
use crate::{
ensemble::{Ensemble, PBack, PSimEvent, PTNode, Referent},
Error,
};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct Delay {
amount: u128,
}
impl Delay {
pub fn zero() -> Self {
Self { amount: 0 }
}
pub fn from_amount(amount: u128) -> Self {
Self { amount }
}
pub fn is_zero(self) -> bool {
self.amount == 0
}
pub fn amount(self) -> u128 {
self.amount
}
#[must_use]
pub fn checked_add(self, rhs: Self) -> Option<Self> {
self.amount.checked_add(rhs.amount).map(Delay::from_amount)
}
}
impl From<u128> for Delay {
fn from(value: u128) -> Self {
Self::from_amount(value)
}
}
#[derive(Debug, Clone)]
pub struct TNode {
pub p_self: PBack,
pub p_driver: PBack,
pub delay: Delay,
}
impl Recast<PBack> for TNode {
fn recast<R: Recaster<Item = PBack>>(
&mut self,
recaster: &R,
) -> Result<(), <R as Recaster>::Item> {
self.p_self.recast(recaster)?;
self.p_driver.recast(recaster)
}
}
impl TNode {
pub fn new(p_self: PBack, p_driver: PBack, delay: Delay) -> Self {
Self {
p_self,
p_driver,
delay,
}
}
pub fn delay(&self) -> Delay {
self.delay
}
}
#[derive(Debug, Clone)]
pub struct SimultaneousEvents {
pub tnode_drives: Vec<PTNode>,
}
impl Recast<PTNode> for SimultaneousEvents {
fn recast<R: Recaster<Item = PTNode>>(
&mut self,
recaster: &R,
) -> Result<(), <R as Recaster>::Item> {
self.tnode_drives.recast(recaster)
}
}
#[derive(Debug, Clone)]
pub struct Delayer {
pub current_time: Delay,
pub delayed_events: OrdArena<PSimEvent, Delay, SimultaneousEvents>,
}
impl Recast<PTNode> for Delayer {
fn recast<R: Recaster<Item = PTNode>>(
&mut self,
recaster: &R,
) -> Result<(), <R as Recaster>::Item> {
self.delayed_events.recast(recaster)
}
}
impl Delayer {
pub fn new() -> Self {
Self {
current_time: Delay::zero(),
delayed_events: OrdArena::new(),
}
}
pub fn compress(&mut self) {
self.delayed_events.compress_and_shrink();
}
pub fn insert_delayed_tnode_event(&mut self, p_tnode: PTNode, delay: Delay) {
let future_time = self.current_time.checked_add(delay).unwrap();
if let Some((p, order)) = self.delayed_events.find_similar_key(&future_time) {
if order.is_eq() {
self.delayed_events
.get_val_mut(p)
.unwrap()
.tnode_drives
.push(p_tnode);
} else {
let _ = self
.delayed_events
.insert_linear(p, 2, future_time, SimultaneousEvents {
tnode_drives: vec![p_tnode],
});
}
} else {
self.delayed_events
.insert_empty(future_time, SimultaneousEvents {
tnode_drives: vec![p_tnode],
})
.unwrap();
}
}
pub fn are_delayed_events_empty(&self) -> bool {
self.delayed_events.is_empty()
}
#[must_use]
pub fn peek_next_event_time(&self) -> Option<Delay> {
let p_min = self.delayed_events.first()?;
self.delayed_events.get_key(p_min).copied()
}
#[must_use]
pub fn pop_next_simultaneous_events(&mut self) -> Option<(Delay, SimultaneousEvents)> {
let p_min = self.delayed_events.first()?;
self.delayed_events.remove(p_min)
}
}
impl Ensemble {
#[must_use]
pub fn make_tnode(&mut self, p_source: PBack, p_driver: PBack, delay: Delay) -> PTNode {
self.tnodes.insert_with(|p_tnode| {
let p_driver = self
.backrefs
.insert_key(p_driver, Referent::Driver(p_tnode))
.unwrap();
let p_self = self
.backrefs
.insert_key(p_source, Referent::ThisTNode(p_tnode))
.unwrap();
TNode::new(p_self, p_driver, delay)
})
}
pub fn run(&mut self, delay: Delay) -> Result<(), Error> {
self.restart_request_phase()?;
let final_time = self.delayer.current_time.checked_add(delay).unwrap();
while let Some(next_time) = self.delayer.peek_next_event_time() {
if next_time > final_time {
break
}
let (time, events) = self.delayer.pop_next_simultaneous_events().unwrap();
self.delayer.current_time = time;
for p_tnode in events.tnode_drives.iter().copied() {
if let Some(tnode) = self.tnodes.get(p_tnode) {
let p_driver = tnode.p_driver;
self.request_value(p_driver)?;
}
}
for p_tnode in events.tnode_drives.iter().copied() {
if let Some(tnode) = self.tnodes.get(p_tnode) {
let val = self.backrefs.get_val(tnode.p_driver).unwrap().val;
let p_self = tnode.p_self;
self.change_value(p_self, val, NonZeroU64::new(1).unwrap())
.unwrap();
}
}
self.restart_request_phase()?;
}
self.delayer.current_time = final_time;
Ok(())
}
}
impl Default for Delayer {
fn default() -> Self {
Self::new()
}
}