use std::collections::BTreeMap; use crate::events::{ProcessEvent, ProcessEventKind}; type ProcessEventListener = Box; pub trait BacktestProcessMod { fn name(&self) -> &str; fn install(&mut self, bus: &mut ProcessEventBus); } #[derive(Default)] pub struct BacktestProcessModLoader { modules: Vec>, } impl BacktestProcessModLoader { pub fn new() -> Self { Self::default() } pub fn register(&mut self, module: M) where M: BacktestProcessMod + 'static, { self.modules.push(Box::new(module)); } pub fn module_names(&self) -> Vec { self.modules .iter() .map(|module| module.name().to_string()) .collect() } pub fn install_all(&mut self, bus: &mut ProcessEventBus) -> Vec { self.modules .iter_mut() .map(|module| { let name = module.name().to_string(); module.install(bus); name }) .collect() } pub fn install_enabled( &mut self, bus: &mut ProcessEventBus, enabled_names: &[String], ) -> Vec { if enabled_names.is_empty() { return self.install_all(bus); } self.modules .iter_mut() .filter(|module| { enabled_names .iter() .any(|name| name.eq_ignore_ascii_case(module.name())) }) .map(|module| { let name = module.name().to_string(); module.install(bus); name }) .collect() } } #[derive(Default)] pub struct ProcessEventBus { listeners: BTreeMap>, any_listeners: Vec, } impl ProcessEventBus { pub fn new() -> Self { Self::default() } pub fn add_listener(&mut self, kind: ProcessEventKind, listener: F) where F: FnMut(&ProcessEvent) + 'static, { self.listeners .entry(kind) .or_default() .push(Box::new(listener)); } pub fn prepend_listener(&mut self, kind: ProcessEventKind, listener: F) where F: FnMut(&ProcessEvent) + 'static, { self.listeners .entry(kind) .or_default() .insert(0, Box::new(listener)); } pub fn add_any_listener(&mut self, listener: F) where F: FnMut(&ProcessEvent) + 'static, { self.any_listeners.push(Box::new(listener)); } pub fn install_mod(&mut self, module: &mut M) where M: BacktestProcessMod, { module.install(self); } pub fn install_mod_loader(&mut self, loader: &mut BacktestProcessModLoader) -> Vec { loader.install_all(self) } pub fn install_enabled_mods( &mut self, loader: &mut BacktestProcessModLoader, enabled_names: &[String], ) -> Vec { loader.install_enabled(self, enabled_names) } pub fn publish(&mut self, event: &ProcessEvent) { if let Some(listeners) = self.listeners.get_mut(&event.kind) { for listener in listeners { listener(event); } } for listener in &mut self.any_listeners { listener(event); } } }