use std::sync::Arc;
#[async_trait::async_trait]
pub trait Module: Send + Sync {
type AppConfig;
fn name(&self) -> &'static str {
std::any::type_name::<Self>()
}
async fn init(&self) {}
fn configure(&self, cfg: &mut Self::AppConfig);
}
pub struct Modules<TAppConfig> {
modules: Vec<Arc<dyn Module<AppConfig = TAppConfig>>>,
}
impl<TAppConfig> Modules<TAppConfig> {
pub fn new() -> Self {
Self {
modules: Vec::new(),
}
}
pub fn add<TModule>(mut self) -> Self
where
TModule: Module<AppConfig = TAppConfig> + 'static + Default,
{
self.modules.push(Arc::new(TModule::default()));
self
}
pub fn arc(self) -> Arc<Self> {
Arc::new(self)
}
pub async fn init(&self) {
for module in &self.modules {
module.init().await;
}
}
pub fn configure(&self, cfg: &mut TAppConfig) {
for module in &self.modules {
module.configure(cfg);
}
}
}
#[cfg(test)]
#[test]
fn modules_test() {
use futures::executor::block_on;
use crate::modules::*;
#[derive(Default)]
struct MyModule;
impl Module for MyModule {
type AppConfig = String;
fn configure(&self, cfg: &mut Self::AppConfig) {
*cfg += "Configured by MyModule. ";
println!("Configuring MyModule");
}
}
let modules = Modules::new().add::<MyModule>().arc();
let modules_clone = modules.clone();
block_on(async move {
modules_clone.init().await;
});
block_on(async move {
let mut config = String::new();
modules.clone().configure(&mut config);
});
}