use crate::effect::{Correlation, EffectSink, TimerId};
use crate::error::CoreError;
use crate::platform::MaybeSend;
use crate::tick::Tick;
use std::collections::HashMap;
pub trait Module: MaybeSend + 'static {
fn name(&self) -> &'static str;
fn accepts(&self, tick: &Tick) -> bool;
fn handle(&mut self, tick: &Tick, now_ms: u64, out: &mut EffectSink) -> Result<(), CoreError>;
fn on_start(&mut self, out: &mut EffectSink) -> Result<(), CoreError> {
let _ = out;
Ok(())
}
fn on_stop(&mut self, out: &mut EffectSink) -> Result<(), CoreError> {
let _ = out;
Ok(())
}
}
#[derive(Default)]
pub(crate) struct CorrelationMap {
map: HashMap<Correlation, usize>,
}
impl CorrelationMap {
pub fn register(&mut self, corr: Correlation, module_index: usize) {
self.map.insert(corr, module_index);
}
pub fn consume(&mut self, corr: &Correlation) -> Option<usize> {
self.map.remove(corr)
}
pub fn peek(&self, corr: &Correlation) -> Option<usize> {
self.map.get(corr).copied()
}
}
#[derive(Default)]
pub(crate) struct TimerMap {
map: HashMap<TimerId, usize>,
}
impl TimerMap {
pub fn register(&mut self, id: TimerId, module_index: usize) {
self.map.insert(id, module_index);
}
pub fn peek(&self, id: &TimerId) -> Option<usize> {
self.map.get(id).copied()
}
pub fn remove(&mut self, id: &TimerId) {
self.map.remove(id);
}
#[cfg(test)]
pub fn len(&self) -> usize {
self.map.len()
}
}
pub struct ModuleHost {
modules: Vec<Box<dyn Module>>,
}
impl ModuleHost {
pub fn new() -> Self {
Self {
modules: Vec::new(),
}
}
pub fn register(&mut self, m: impl Module + 'static) {
self.modules.push(Box::new(m));
}
pub fn module_count(&self) -> usize {
self.modules.len()
}
pub fn dispatch_inbound(
&mut self,
tick: &Tick,
now_ms: u64,
out: &mut EffectSink,
) -> Result<Option<usize>, CoreError> {
for (idx, m) in self.modules.iter_mut().enumerate() {
if m.accepts(tick) {
m.handle(tick, now_ms, out)
.map_err(|e| CoreError::ModuleError {
module: m.name(),
source: Box::new(e),
})?;
return Ok(Some(idx));
}
}
Ok(None)
}
pub fn dispatch_reply(
&mut self,
module_index: usize,
tick: &Tick,
now_ms: u64,
out: &mut EffectSink,
) -> Result<(), CoreError> {
let m = self
.modules
.get_mut(module_index)
.ok_or(CoreError::NoHandler("module_index out of bounds"))?;
m.handle(tick, now_ms, out)
.map_err(|e| CoreError::ModuleError {
module: m.name(),
source: Box::new(e),
})
}
pub fn start_one(&mut self, idx: usize, out: &mut EffectSink) -> Result<(), CoreError> {
let m = self.modules.get_mut(idx).ok_or(CoreError::NoHandler(
"start_one: module_index out of bounds",
))?;
m.on_start(out).map_err(|e| CoreError::ModuleError {
module: m.name(),
source: Box::new(e),
})
}
pub fn start_all(&mut self, out: &mut EffectSink) -> Result<(), CoreError> {
for m in &mut self.modules {
m.on_start(out).map_err(|e| CoreError::ModuleError {
module: m.name(),
source: Box::new(e),
})?;
}
Ok(())
}
pub fn stop_all(&mut self, out: &mut EffectSink) -> Result<(), CoreError> {
for m in self.modules.iter_mut().rev() {
m.on_stop(out).map_err(|e| CoreError::ModuleError {
module: m.name(),
source: Box::new(e),
})?;
}
Ok(())
}
}
impl Default for ModuleHost {
fn default() -> Self {
Self::new()
}
}