use crate::{Container, ControllerRegistration, Error, Guard, ProviderRegistration, Router};
use std::any::TypeId;
use std::collections::HashSet;
use std::sync::Arc;
#[derive(Clone)]
pub struct GuardRegistration {
pub type_id: TypeId,
pub type_name: &'static str,
pub factory: fn(&Container) -> Result<Arc<dyn Guard>, Error>,
}
impl std::fmt::Debug for GuardRegistration {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("GuardRegistration")
.field("type_id", &self.type_id)
.field("type_name", &self.type_name)
.finish()
}
}
#[derive(Debug, Clone, Default)]
pub struct ModuleMetadata {
pub global: bool,
pub name: Option<String>,
pub version: Option<String>,
pub description: Option<String>,
}
impl ModuleMetadata {
pub fn new() -> Self {
Self::default()
}
pub fn global(mut self) -> Self {
self.global = true;
self
}
pub fn name(mut self, name: &str) -> Self {
self.name = Some(name.to_string());
self
}
pub fn version(mut self, version: &str) -> Self {
self.version = Some(version.to_string());
self
}
pub fn description(mut self, description: &str) -> Self {
self.description = Some(description.to_string());
self
}
}
pub trait ModuleExt: Send + Sync + 'static {
fn providers(&self) -> Vec<ProviderRegistration> {
vec![]
}
fn controllers(&self) -> Vec<ControllerRegistration> {
vec![]
}
fn guards(&self) -> Vec<GuardRegistration> {
vec![]
}
fn imports(&self) -> Vec<Box<dyn ModuleExt>> {
vec![]
}
fn exports(&self) -> Vec<TypeId> {
vec![]
}
fn re_exports(&self) -> Vec<Box<dyn ModuleExt>> {
vec![]
}
fn metadata(&self) -> ModuleMetadata {
ModuleMetadata::default()
}
fn on_module_init(&self, _container: &Container) -> Result<(), Error> {
Ok(())
}
fn on_module_destroy(&self) -> Result<(), Error> {
Ok(())
}
}
#[derive(Clone)]
pub struct DynamicModule {
pub name: String,
providers: Vec<ProviderRegistration>,
controllers: Vec<ControllerRegistration>,
guards: Vec<GuardRegistration>,
imports: Vec<Arc<dyn ModuleExt>>,
exports: Vec<TypeId>,
re_exports: Vec<Arc<dyn ModuleExt>>,
metadata: ModuleMetadata,
export_all: bool,
}
impl DynamicModule {
pub fn new(name: &str) -> Self {
Self {
name: name.to_string(),
providers: vec![],
controllers: vec![],
guards: vec![],
imports: vec![],
exports: vec![],
re_exports: vec![],
metadata: ModuleMetadata::default().name(name),
export_all: false,
}
}
pub fn with_provider(mut self, provider: ProviderRegistration) -> Self {
self.providers.push(provider);
self
}
pub fn with_providers(mut self, providers: Vec<ProviderRegistration>) -> Self {
self.providers.extend(providers);
self
}
pub fn with_controller(mut self, controller: ControllerRegistration) -> Self {
self.controllers.push(controller);
self
}
pub fn with_controllers(mut self, controllers: Vec<ControllerRegistration>) -> Self {
self.controllers.extend(controllers);
self
}
pub fn with_guard(mut self, guard: GuardRegistration) -> Self {
self.guards.push(guard);
self
}
pub fn with_guards(mut self, guards: Vec<GuardRegistration>) -> Self {
self.guards.extend(guards);
self
}
pub fn import<M: ModuleExt + Clone + 'static>(mut self, module: M) -> Self {
self.imports.push(Arc::new(module));
self
}
pub fn import_boxed(mut self, module: Box<dyn ModuleExt>) -> Self {
self.imports.push(Arc::from(module));
self
}
pub fn export<T: 'static>(mut self) -> Self {
self.exports.push(TypeId::of::<T>());
self
}
pub fn export_id(mut self, type_id: TypeId) -> Self {
self.exports.push(type_id);
self
}
pub fn export_all(mut self) -> Self {
self.export_all = true;
self
}
pub fn re_export<M: ModuleExt + Clone + 'static>(mut self, module: M) -> Self {
self.re_exports.push(Arc::new(module));
self
}
pub fn global(mut self) -> Self {
self.metadata.global = true;
self
}
pub fn with_metadata(mut self, metadata: ModuleMetadata) -> Self {
self.metadata = metadata;
self
}
}
impl ModuleExt for DynamicModule {
fn providers(&self) -> Vec<ProviderRegistration> {
self.providers.clone()
}
fn controllers(&self) -> Vec<ControllerRegistration> {
self.controllers.clone()
}
fn guards(&self) -> Vec<GuardRegistration> {
self.guards.clone()
}
fn imports(&self) -> Vec<Box<dyn ModuleExt>> {
self.imports
.iter()
.map(|m| Box::new(ArcModule(m.clone())) as Box<dyn ModuleExt>)
.collect()
}
fn exports(&self) -> Vec<TypeId> {
if self.export_all {
self.providers.iter().map(|p| p.type_id).collect()
} else {
self.exports.clone()
}
}
fn re_exports(&self) -> Vec<Box<dyn ModuleExt>> {
self.re_exports
.iter()
.map(|m| Box::new(ArcModule(m.clone())) as Box<dyn ModuleExt>)
.collect()
}
fn metadata(&self) -> ModuleMetadata {
self.metadata.clone()
}
}
struct ArcModule(Arc<dyn ModuleExt>);
impl ModuleExt for ArcModule {
fn providers(&self) -> Vec<ProviderRegistration> {
self.0.providers()
}
fn controllers(&self) -> Vec<ControllerRegistration> {
self.0.controllers()
}
fn guards(&self) -> Vec<GuardRegistration> {
self.0.guards()
}
fn imports(&self) -> Vec<Box<dyn ModuleExt>> {
self.0.imports()
}
fn exports(&self) -> Vec<TypeId> {
self.0.exports()
}
fn re_exports(&self) -> Vec<Box<dyn ModuleExt>> {
self.0.re_exports()
}
fn metadata(&self) -> ModuleMetadata {
self.0.metadata()
}
}
pub fn collect_all_exports(module: &dyn ModuleExt) -> HashSet<TypeId> {
let mut exports = HashSet::new();
for type_id in module.exports() {
exports.insert(type_id);
}
for re_export in module.re_exports() {
for type_id in collect_all_exports(re_export.as_ref()) {
exports.insert(type_id);
}
}
exports
}
#[derive(Default)]
pub struct ModuleRegistry {
registered: HashSet<TypeId>,
global_modules: Vec<Arc<dyn ModuleExt>>,
guards: Vec<Arc<dyn Guard>>,
}
impl ModuleRegistry {
pub fn new() -> Self {
Self::default()
}
pub fn is_registered<M: 'static>(&self) -> bool {
self.registered.contains(&TypeId::of::<M>())
}
pub fn mark_registered<M: 'static>(&mut self) {
self.registered.insert(TypeId::of::<M>());
}
pub fn register_module(
&mut self,
container: &Container,
router: &mut Router,
module: &dyn ModuleExt,
) -> Result<(), Error> {
let module_name = module
.metadata()
.name
.unwrap_or_else(|| "UnnamedModule".to_string());
tracing::debug!(module = %module_name, "Registering module");
for imported in module.imports() {
self.register_module(container, router, imported.as_ref())?;
}
let globals: Vec<Arc<dyn ModuleExt>> = self.global_modules.clone();
for global in globals {
self.register_module(container, router, global.as_ref())?;
}
for provider_reg in module.providers() {
(provider_reg.register_fn)(container);
tracing::trace!(
module = %module_name,
provider = provider_reg.type_name,
"Provider registered"
);
}
for guard_reg in module.guards() {
match (guard_reg.factory)(container) {
Ok(guard) => {
self.guards.push(guard);
tracing::trace!(
module = %module_name,
guard = guard_reg.type_name,
"Guard registered"
);
}
Err(e) => {
tracing::warn!(
module = %module_name,
guard = guard_reg.type_name,
error = %e,
"Failed to register guard"
);
}
}
}
for controller_reg in module.controllers() {
match (controller_reg.factory)(container) {
Ok(controller_instance) => {
if let Err(e) =
(controller_reg.route_registrar)(container, router, controller_instance)
{
tracing::warn!(
module = %module_name,
controller = controller_reg.type_name,
error = %e,
"Failed to register controller routes"
);
} else {
tracing::trace!(
module = %module_name,
controller = controller_reg.type_name,
base_path = controller_reg.base_path,
"Controller registered"
);
}
}
Err(e) => {
tracing::warn!(
module = %module_name,
controller = controller_reg.type_name,
error = %e,
"Failed to instantiate controller"
);
}
}
}
module.on_module_init(container)?;
tracing::debug!(module = %module_name, "Module registration complete");
Ok(())
}
pub fn add_global_module<M: ModuleExt + 'static>(&mut self, module: M) {
self.global_modules.push(Arc::new(module));
}
pub fn add_global_module_boxed(&mut self, module: Box<dyn ModuleExt>) {
self.global_modules.push(Arc::from(module));
}
pub fn guards(&self) -> &[Arc<dyn Guard>] {
&self.guards
}
}
pub struct ModuleBuilder {
inner: DynamicModule,
}
impl ModuleBuilder {
pub fn new(name: &str) -> Self {
Self {
inner: DynamicModule::new(name),
}
}
pub fn provider(mut self, provider: ProviderRegistration) -> Self {
self.inner = self.inner.with_provider(provider);
self
}
pub fn controller(mut self, controller: ControllerRegistration) -> Self {
self.inner = self.inner.with_controller(controller);
self
}
pub fn guard(mut self, guard: GuardRegistration) -> Self {
self.inner = self.inner.with_guard(guard);
self
}
pub fn import<M: ModuleExt + Clone + 'static>(mut self, module: M) -> Self {
self.inner = self.inner.import(module);
self
}
pub fn export<T: 'static>(mut self) -> Self {
self.inner = self.inner.export::<T>();
self
}
pub fn export_all(mut self) -> Self {
self.inner = self.inner.export_all();
self
}
pub fn re_export<M: ModuleExt + Clone + 'static>(mut self, module: M) -> Self {
self.inner = self.inner.re_export(module);
self
}
pub fn global(mut self) -> Self {
self.inner = self.inner.global();
self
}
pub fn build(self) -> DynamicModule {
self.inner
}
}
#[macro_export]
macro_rules! provider_registration {
($type:ty, $factory:expr) => {
$crate::ProviderRegistration {
type_id: std::any::TypeId::of::<$type>(),
type_name: std::any::type_name::<$type>(),
register_fn: |container| {
let instance = $factory;
container.register(instance);
},
}
};
}
#[macro_export]
macro_rules! guard_registration {
($type:ty, $factory:expr) => {
$crate::module::GuardRegistration {
type_id: std::any::TypeId::of::<$type>(),
type_name: std::any::type_name::<$type>(),
factory: |_container| {
let guard = $factory;
Ok(std::sync::Arc::new(guard) as std::sync::Arc<dyn $crate::Guard>)
},
}
};
}
#[cfg(test)]
mod tests {
use super::*;
#[allow(dead_code)]
#[derive(Clone)]
struct TestModule;
impl ModuleExt for TestModule {
fn providers(&self) -> Vec<ProviderRegistration> {
vec![]
}
fn controllers(&self) -> Vec<ControllerRegistration> {
vec![]
}
fn imports(&self) -> Vec<Box<dyn ModuleExt>> {
vec![]
}
fn exports(&self) -> Vec<TypeId> {
vec![]
}
fn metadata(&self) -> ModuleMetadata {
ModuleMetadata::new().name("TestModule")
}
}
#[test]
fn test_dynamic_module_creation() {
let module = DynamicModule::new("TestModule");
assert_eq!(module.name, "TestModule");
assert!(module.providers.is_empty());
assert!(module.controllers.is_empty());
}
#[test]
fn test_dynamic_module_export_all() {
let module = DynamicModule::new("TestModule").export_all();
assert!(module.export_all);
}
#[test]
fn test_module_builder() {
let module = ModuleBuilder::new("MyModule").export_all().global().build();
assert!(module.export_all);
assert!(module.metadata.global);
}
#[test]
fn test_module_metadata() {
let metadata = ModuleMetadata::new()
.name("MyModule")
.version("1.0.0")
.description("A test module")
.global();
assert_eq!(metadata.name, Some("MyModule".to_string()));
assert_eq!(metadata.version, Some("1.0.0".to_string()));
assert_eq!(metadata.description, Some("A test module".to_string()));
assert!(metadata.global);
}
#[test]
fn test_collect_all_exports() {
#[derive(Clone)]
struct InnerModule;
impl ModuleExt for InnerModule {
fn exports(&self) -> Vec<TypeId> {
vec![TypeId::of::<String>()]
}
}
#[derive(Clone)]
struct OuterModule;
impl ModuleExt for OuterModule {
fn exports(&self) -> Vec<TypeId> {
vec![TypeId::of::<i32>()]
}
fn re_exports(&self) -> Vec<Box<dyn ModuleExt>> {
vec![Box::new(InnerModule)]
}
}
let exports = collect_all_exports(&OuterModule);
assert!(exports.contains(&TypeId::of::<String>()));
assert!(exports.contains(&TypeId::of::<i32>()));
}
#[test]
fn test_module_registry_creation() {
let registry = ModuleRegistry::new();
assert!(registry.guards().is_empty());
}
#[test]
fn test_guard_registration_debug() {
let reg = GuardRegistration {
type_id: TypeId::of::<String>(),
type_name: "TestGuard",
factory: |_| Err(Error::Internal("test".to_string())),
};
let debug_str = format!("{:?}", reg);
assert!(debug_str.contains("TestGuard"));
}
}