diff --git a/pagetop/src/core/module/all.rs b/pagetop/src/core/module/all.rs index 2e499f23..e902c1ec 100644 --- a/pagetop/src/core/module/all.rs +++ b/pagetop/src/core/module/all.rs @@ -1,14 +1,20 @@ use crate::{Lazy, app, run_now, trace}; use crate::db::*; -use super::ModuleTrait; +use super::{ExtensionTrait, ModuleTrait}; -use std::sync::RwLock; +use std::sync::{Arc, RwLock}; +use std::collections::HashMap; // Módulos registrados. static MODULES: Lazy>> = Lazy::new(|| { RwLock::new(Vec::new()) }); +// Extensiones registradas. +static EXTENSIONS: Lazy>>>> = Lazy::new(|| { + RwLock::new(HashMap::new()) +}); + pub fn register_module(module: &'static dyn ModuleTrait) { let mut list: Vec<&dyn ModuleTrait> = Vec::new(); add_to(&mut list, module); @@ -17,11 +23,24 @@ pub fn register_module(module: &'static dyn ModuleTrait) { } fn add_to(list: &mut Vec<&dyn ModuleTrait>, module: &'static dyn ModuleTrait) { - if !MODULES.read().unwrap().iter().any(|m| m.name() == module.name()) { - if !list.iter().any(|m| m.name() == module.name()) { + if !MODULES.read().unwrap().iter().any(|m| m.type_name() == module.type_name()) { + if !list.iter().any(|m| m.type_name() == module.type_name()) { trace::debug!("Registering \"{}\" module", module.single_name()); list.push(module); + + let mut hmap = EXTENSIONS.write().unwrap(); + for e in module.extensions().iter() { + if let Some(extensions) = hmap.get_mut(e.type_name()) { + let v = Arc::get_mut(extensions).unwrap(); + v.push(*e); + v.sort_by_key(|e| e.weight()); + } else { + hmap.insert(e.type_name(), Arc::new(vec![*e])); + } + } + + let mut dependencies = module.dependencies(); dependencies.reverse(); for d in dependencies.iter() { @@ -37,6 +56,13 @@ pub fn modules(cfg: &mut app::web::ServiceConfig) { } } +pub fn extensions(type_name: &'static str) -> Option>> { + match EXTENSIONS.read().unwrap().get(type_name) { + Some(extensions) => Some(extensions.clone()), + _ => None, + } +} + #[cfg(any(feature = "mysql", feature = "postgres", feature = "sqlite"))] pub fn migrations() { run_now({ diff --git a/pagetop/src/core/module/definition.rs b/pagetop/src/core/module/definition.rs index baaadd98..58a8d4ea 100644 --- a/pagetop/src/core/module/definition.rs +++ b/pagetop/src/core/module/definition.rs @@ -1,15 +1,16 @@ -use crate::app; -use crate::util::partial_type_name; +use crate::{app, util}; #[cfg(any(feature = "mysql", feature = "postgres", feature = "sqlite"))] use crate::db; +use super::ExtensionTrait; + pub trait BaseModule { fn type_name(&self) -> &'static str; fn single_name(&self) -> &'static str; - fn qualified_name(&self, last: usize) -> &'static str; + fn qualified_name(&self, last: u8) -> &'static str; } /// Los módulos deben implementar este *trait*. @@ -22,19 +23,23 @@ pub trait ModuleTrait: BaseModule + Send + Sync { None } - fn dependencies(&self) -> Vec<&'static dyn ModuleTrait> { - vec![] - } - #[allow(unused_variables)] fn configure_module(&self, cfg: &mut app::web::ServiceConfig) { } + fn extensions(&self) -> Vec<&'static dyn ExtensionTrait> { + vec![] + } + #[cfg(any(feature = "mysql", feature = "postgres", feature = "sqlite"))] #[allow(unused_variables)] fn migrations(&self) -> Vec> { vec![] } + + fn dependencies(&self) -> Vec<&'static dyn ModuleTrait> { + vec![] + } } impl BaseModule for M { @@ -43,10 +48,10 @@ impl BaseModule for M { } fn single_name(&self) -> &'static str { - partial_type_name(std::any::type_name::(), 1) + util::partial_type_name(std::any::type_name::(), 1) } - fn qualified_name(&self, last: usize) -> &'static str { - partial_type_name(std::any::type_name::(), last) + fn qualified_name(&self, last: u8) -> &'static str { + util::partial_type_name(std::any::type_name::(), last) } } diff --git a/pagetop/src/core/module/extension.rs b/pagetop/src/core/module/extension.rs new file mode 100644 index 00000000..e8b8107c --- /dev/null +++ b/pagetop/src/core/module/extension.rs @@ -0,0 +1,30 @@ +use crate::util; + +pub trait BaseExtension { + fn type_name(&self) -> &'static str; + + fn single_name(&self) -> &'static str; + + fn qualified_name(&self, last: u8) -> &'static str; +} + +/// Las extensiones deben extender este *trait*. +pub trait ExtensionTrait: BaseExtension + Send + Sync { + fn weight(&self) -> i8 { + 0 + } +} + +impl BaseExtension for E { + fn type_name(&self) -> &'static str { + std::any::type_name::() + } + + fn single_name(&self) -> &'static str { + util::partial_type_name(std::any::type_name::(), 1) + } + + fn qualified_name(&self, last: u8) -> &'static str { + util::partial_type_name(std::any::type_name::(), last) + } +} diff --git a/pagetop/src/core/module/mod.rs b/pagetop/src/core/module/mod.rs index 720d806c..d72bd48d 100644 --- a/pagetop/src/core/module/mod.rs +++ b/pagetop/src/core/module/mod.rs @@ -3,6 +3,14 @@ pub use definition::{ BaseModule, ModuleTrait, }; +mod extension; +pub use extension::{ + BaseExtension, + ExtensionTrait, +}; pub(crate) mod all; -pub use all::register_module; \ No newline at end of file +pub use all::{ + extensions, + register_module +}; diff --git a/pagetop/src/core/response/page/component.rs b/pagetop/src/core/response/page/component.rs index aa1160b1..0bbc3abf 100644 --- a/pagetop/src/core/response/page/component.rs +++ b/pagetop/src/core/response/page/component.rs @@ -1,6 +1,6 @@ use crate::html::{Markup, html}; use crate::core::response::page::PageAssets; -use crate::util::partial_type_name; +use crate::util; pub use std::any::Any as AnyComponent; @@ -9,7 +9,7 @@ pub trait BaseComponent { fn single_name(&self) -> &'static str; - fn qualified_name(&self, last: usize) -> &'static str; + fn qualified_name(&self, last: u8) -> &'static str; } pub trait ComponentTrait: AnyComponent + BaseComponent + Send + Sync { @@ -52,11 +52,11 @@ impl BaseComponent for C { } fn single_name(&self) -> &'static str { - partial_type_name(std::any::type_name::(), 1) + util::partial_type_name(std::any::type_name::(), 1) } - fn qualified_name(&self, last: usize) -> &'static str { - partial_type_name(std::any::type_name::(), last) + fn qualified_name(&self, last: u8) -> &'static str { + util::partial_type_name(std::any::type_name::(), last) } } diff --git a/pagetop/src/core/theme/definition.rs b/pagetop/src/core/theme/definition.rs index 1d6df035..130dfdac 100644 --- a/pagetop/src/core/theme/definition.rs +++ b/pagetop/src/core/theme/definition.rs @@ -3,14 +3,14 @@ use crate::config::SETTINGS; use crate::html::{Markup, html}; use crate::core::response::page::{ComponentTrait, Favicon, Page, PageAssets}; use crate::base::component::Chunck; -use crate::util::partial_type_name; +use crate::util; pub trait BaseTheme { fn type_name(&self) -> &'static str; fn single_name(&self) -> &'static str; - fn qualified_name(&self, last: usize) -> &'static str; + fn qualified_name(&self, last: u8) -> &'static str; } /// Los temas deben implementar este "trait". @@ -143,10 +143,10 @@ impl BaseTheme for T { } fn single_name(&self) -> &'static str { - partial_type_name(std::any::type_name::(), 1) + util::partial_type_name(std::any::type_name::(), 1) } - fn qualified_name(&self, last: usize) -> &'static str { - partial_type_name(std::any::type_name::(), last) + fn qualified_name(&self, last: u8) -> &'static str { + util::partial_type_name(std::any::type_name::(), last) } } diff --git a/pagetop/src/util.rs b/pagetop/src/util.rs index ca4a96fc..3190b641 100644 --- a/pagetop/src/util.rs +++ b/pagetop/src/util.rs @@ -47,11 +47,12 @@ macro_rules! theme_static_files { }}; } -pub(crate) fn partial_type_name(type_name: &'static str, last: usize) -> &'static str { +pub(crate) fn partial_type_name(type_name: &'static str, last: u8) -> &'static str { if last == 0 { return type_name; } let positions: Vec<_> = type_name.rmatch_indices("::").collect(); + let last: usize = last as usize; if positions.len() < last { return type_name; }