#[cfg(any(feature="seq_mode", feature="wasm_mode"))]
use std::cell::UnsafeCell;
#[cfg(any(feature="seq_mode", feature="wasm_mode"))]
use std::ops::Deref;
#[cfg(feature="cons_mode")]
use libc::*;
use crate::simulation::error::*;
use crate::simulation::specs::SpecsRepr;
use crate::simulation::point::Point;
use crate::simulation::event::*;
#[cfg(any(feature="seq_mode", feature="wasm_mode"))]
use crate::simulation;
#[cfg(any(feature="seq_mode", feature="wasm_mode"))]
use crate::simulation::utils::priority_queue::PriorityQueue;
#[cfg(any(feature="seq_mode", feature="wasm_mode"))]
pub struct EventQueue {
time: UnsafeCell<f64>,
pq: UnsafeCell<PriorityQueue<(f64, isize), EventRepr>>
}
#[cfg(any(feature="seq_mode", feature="wasm_mode"))]
impl EventQueue {
pub fn new(specs: &SpecsRepr) -> EventQueue {
EventQueue {
time: UnsafeCell::new(specs.start_time),
pq: UnsafeCell::new(PriorityQueue::new())
}
}
#[inline]
pub fn enqueue_event(&self, event_time: f64, priority: isize, comp: EventRepr, p: &Point) {
assert!(event_time >= p.time, "The event time cannot be less than the current modeling time");
let pq = self.pq.get();
unsafe {
(*pq).enqueue((event_time, - priority), comp);
}
}
#[inline]
pub fn enqueue_io_event(&self, event_time: f64, priority: isize, comp: EventRepr, p: &Point) {
self.enqueue_event(event_time, priority, comp, p)
}
pub fn run_events(&self, including_current: bool, p: &Point) -> simulation::Result<()> {
loop {
let ((t2, pri2), c2) = unsafe {
let pq = self.pq.get();
let t0 = self.time.get();
match (*pq).minimal_key() {
Some((t2, _)) if *t2 < *t0 => {
panic!("The time value is too small. The event queue is desynchronized");
}
Some((t2, _)) if *t2 < p.time || (including_current && *t2 == p.time) => {
*t0 = *t2;
}
_ => {
break;
}
}
(*pq).dequeue()
};
let run = p.run;
let specs = &run.specs;
let t0 = specs.start_time;
let dt = specs.dt;
let n2 = ((t2 - t0) / dt).floor() as usize;
let p2 = Point {
run: p.run,
time: t2,
priority: -pri2,
minimal_priority: p.minimal_priority,
iteration: n2,
phase: -1
};
match c2.call_event(&p2) {
Result::Ok(()) => (),
Result::Err(Error::Cancel) => (),
Result::Err(Error::Other(x)) => {
match x.deref() {
&OtherError::Retry(_) => {
return Result::Err(Error::Other(x.clone()))
},
&OtherError::Panic(_) => {
return Result::Err(Error::Other(x.clone()))
},
&OtherError::IO(_) => {
return Result::Err(Error::Other(x.clone()))
}
}
}
}
}
Result::Ok(())
}
}
#[cfg(feature="cons_mode")]
pub type EventQueue = c_void;
#[cfg(all(feature="cons_mode", not(feature="cons_core_mode")))]
#[cfg_attr(windows, link(name = "dvcompute_core_cons.dll"))]
#[cfg_attr(not(windows), link(name = "dvcompute_core_cons"))]
extern {
#[doc(hidden)]
pub fn create_extern_event_queue(specs: *const SpecsRepr) -> *mut EventQueue;
#[doc(hidden)]
pub fn delete_extern_event_queue(queue: *mut EventQueue);
#[doc(hidden)]
pub fn enqueue_extern_event(queue: *mut EventQueue, event_time: f64, priority: isize, comp: EventRepr, p: *const Point);
#[doc(hidden)]
pub fn enqueue_extern_io_event(queue: *mut EventQueue, event_time: f64, priority: isize, comp: EventRepr, p: *const Point);
#[doc(hidden)]
pub fn run_extern_events(including_current: isize, p: *const Point) -> *mut ErrorRepr;
}
#[cfg(all(feature="cons_mode", feature="cons_core_mode"))]
extern {
#[doc(hidden)]
pub fn create_extern_event_queue(specs: *const SpecsRepr) -> *mut EventQueue;
#[doc(hidden)]
pub fn delete_extern_event_queue(queue: *mut EventQueue);
#[doc(hidden)]
pub fn enqueue_extern_event(queue: *mut EventQueue, event_time: f64, priority: isize, comp: EventRepr, p: *const Point);
#[doc(hidden)]
pub fn enqueue_extern_io_event(queue: *mut EventQueue, event_time: f64, priority: isize, comp: EventRepr, p: *const Point);
#[doc(hidden)]
pub fn run_extern_events(including_current: isize, p: *const Point) -> *mut ErrorRepr;
}