use crate::{SimCx, SimCxl, node_id::NodeId};
use scopeguard::guard;
use std::{
any::{Any, TypeId, type_name},
cell::RefCell,
marker::PhantomData,
mem,
rc::Rc,
};
pub trait Simulator: Any {
fn create_node(&mut self) {}
fn stop_node(&mut self) {}
fn start_node(&mut self) {}
}
pub fn add_simulator<S: Simulator>(simulator: S) {
let simulator = Some(Box::new(simulator) as Box<_>);
SimCxl::with(|cx| {
assert!(cx.executor.node_count() == 1 && !cx.executor.is_final_stopping());
assert!(
cx.simulators_by_type
.insert(TypeId::of::<S>(), cx.simulators.len())
.is_none()
);
cx.simulators.push(simulator);
})
}
fn with_simulator_option<S: Simulator, R>(f: impl FnOnce(Option<&mut S>) -> R) -> R {
if let Some((index, simulator)) = SimCxl::with(|cx| {
let index = *cx.simulators_by_type.get(&TypeId::of::<S>())?;
let simulator = cx.simulators[index]
.take()
.unwrap_or_else(|| panic!("simulator already mutably borrowed: {}", type_name::<S>()));
Some((index, simulator))
}) {
let mut simulator = guard(simulator, |simulator| {
SimCxl::with(|cx| {
assert!(cx.simulators[index].replace(simulator).is_none());
});
});
let simulator: &mut dyn Simulator = &mut **simulator;
f(Some((simulator as &mut dyn Any).downcast_mut().unwrap()))
} else {
f(None)
}
}
pub struct SimulatorHandle<S: Simulator>(PhantomData<Rc<RefCell<S>>>);
impl<S: Simulator> Clone for SimulatorHandle<S> {
fn clone(&self) -> Self {
Self(self.0)
}
}
impl<S: Simulator> SimulatorHandle<S> {
pub fn with<R>(&self, f: impl FnOnce(&mut S) -> R) -> R {
with_simulator_option(|mut x| f(x.as_mut().unwrap()))
}
pub fn get() -> Self {
SimCxl::with(|cx| {
if !cx.simulators_by_type.contains_key(&TypeId::of::<S>()) {
panic!("simulator does not exist: {}", type_name::<S>());
}
});
SimulatorHandle(PhantomData)
}
}
impl<S: NodeSimulator> SimulatorHandle<PerNode<S>> {
pub fn with_node<R>(&self, node: crate::node_id::NodeId, f: impl FnOnce(&mut S) -> R) -> R {
self.with(|s| f(&mut s.simulators[node.to_index()]))
}
pub fn with_current_node<R>(&self, f: impl FnOnce(&mut S) -> R) -> R {
self.with_node(NodeId::current(), f)
}
}
pub(crate) fn for_all_simulators(cx: &SimCx, forward: bool, mut f: impl FnMut(&mut dyn Simulator)) {
let len = cx.with_cx(|cx| cx.simulators.len());
let mut simulator = None;
for i in 0..len {
let index = if forward { i } else { len - 1 - i };
let swap = |s: &mut Option<_>| {
mem::swap(
&mut cx.context.borrow_mut().as_mut().unwrap().simulators[index],
s,
)
};
swap(&mut simulator);
f(&mut **simulator
.as_mut()
.expect("simulator already mutably borrowed"));
swap(&mut simulator);
}
assert_eq!(
cx.context.borrow_mut().as_mut().unwrap().simulators.len(),
len
);
}
pub trait NodeSimulator: 'static {
fn stop_node(&mut self);
fn start_node(&mut self);
}
pub struct PerNode<S> {
simulators: Vec<S>,
new: Box<dyn FnMut() -> S>,
}
impl<S> std::ops::Index<crate::node_id::NodeId> for PerNode<S> {
type Output = S;
fn index(&self, index: crate::node_id::NodeId) -> &Self::Output {
&self.simulators[index.to_index()]
}
}
impl<S> std::ops::IndexMut<crate::node_id::NodeId> for PerNode<S> {
fn index_mut(&mut self, index: crate::node_id::NodeId) -> &mut Self::Output {
&mut self.simulators[index.to_index()]
}
}
impl<S: NodeSimulator> Simulator for PerNode<S> {
fn create_node(&mut self) {
self.simulators.push((self.new)())
}
fn stop_node(&mut self) {
self.simulators[NodeId::current().to_index()].stop_node();
}
fn start_node(&mut self) {
self.simulators[NodeId::current().to_index()].start_node();
}
}
impl<S: NodeSimulator> PerNode<S> {
pub fn new(mut new: Box<dyn FnMut() -> S>) -> Self {
Self {
simulators: vec![new()],
new,
}
}
}