Añade extensiones en módulos para añadir funciones

This commit is contained in:
Manuel Cillero 2022-05-02 20:00:22 +02:00
parent 8f429401eb
commit 9eede3321a
7 changed files with 96 additions and 26 deletions

View file

@ -1,14 +1,20 @@
use crate::{Lazy, app, run_now, trace}; use crate::{Lazy, app, run_now, trace};
use crate::db::*; 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. // Módulos registrados.
static MODULES: Lazy<RwLock<Vec<&dyn ModuleTrait>>> = Lazy::new(|| { static MODULES: Lazy<RwLock<Vec<&dyn ModuleTrait>>> = Lazy::new(|| {
RwLock::new(Vec::new()) RwLock::new(Vec::new())
}); });
// Extensiones registradas.
static EXTENSIONS: Lazy<RwLock<HashMap<&str, Arc<Vec<&dyn ExtensionTrait>>>>> = Lazy::new(|| {
RwLock::new(HashMap::new())
});
pub fn register_module(module: &'static dyn ModuleTrait) { pub fn register_module(module: &'static dyn ModuleTrait) {
let mut list: Vec<&dyn ModuleTrait> = Vec::new(); let mut list: Vec<&dyn ModuleTrait> = Vec::new();
add_to(&mut list, module); 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) { fn add_to(list: &mut Vec<&dyn ModuleTrait>, module: &'static dyn ModuleTrait) {
if !MODULES.read().unwrap().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.name() == module.name()) { if !list.iter().any(|m| m.type_name() == module.type_name()) {
trace::debug!("Registering \"{}\" module", module.single_name()); trace::debug!("Registering \"{}\" module", module.single_name());
list.push(module); 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(); let mut dependencies = module.dependencies();
dependencies.reverse(); dependencies.reverse();
for d in dependencies.iter() { 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<Arc<Vec<&dyn ExtensionTrait>>> {
match EXTENSIONS.read().unwrap().get(type_name) {
Some(extensions) => Some(extensions.clone()),
_ => None,
}
}
#[cfg(any(feature = "mysql", feature = "postgres", feature = "sqlite"))] #[cfg(any(feature = "mysql", feature = "postgres", feature = "sqlite"))]
pub fn migrations() { pub fn migrations() {
run_now({ run_now({

View file

@ -1,15 +1,16 @@
use crate::app; use crate::{app, util};
use crate::util::partial_type_name;
#[cfg(any(feature = "mysql", feature = "postgres", feature = "sqlite"))] #[cfg(any(feature = "mysql", feature = "postgres", feature = "sqlite"))]
use crate::db; use crate::db;
use super::ExtensionTrait;
pub trait BaseModule { pub trait BaseModule {
fn type_name(&self) -> &'static str; fn type_name(&self) -> &'static str;
fn single_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*. /// Los módulos deben implementar este *trait*.
@ -22,19 +23,23 @@ pub trait ModuleTrait: BaseModule + Send + Sync {
None None
} }
fn dependencies(&self) -> Vec<&'static dyn ModuleTrait> {
vec![]
}
#[allow(unused_variables)] #[allow(unused_variables)]
fn configure_module(&self, cfg: &mut app::web::ServiceConfig) { 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"))] #[cfg(any(feature = "mysql", feature = "postgres", feature = "sqlite"))]
#[allow(unused_variables)] #[allow(unused_variables)]
fn migrations(&self) -> Vec<Box<dyn db::MigrationTrait>> { fn migrations(&self) -> Vec<Box<dyn db::MigrationTrait>> {
vec![] vec![]
} }
fn dependencies(&self) -> Vec<&'static dyn ModuleTrait> {
vec![]
}
} }
impl<M: ?Sized + ModuleTrait> BaseModule for M { impl<M: ?Sized + ModuleTrait> BaseModule for M {
@ -43,10 +48,10 @@ impl<M: ?Sized + ModuleTrait> BaseModule for M {
} }
fn single_name(&self) -> &'static str { fn single_name(&self) -> &'static str {
partial_type_name(std::any::type_name::<Self>(), 1) util::partial_type_name(std::any::type_name::<Self>(), 1)
} }
fn qualified_name(&self, last: usize) -> &'static str { fn qualified_name(&self, last: u8) -> &'static str {
partial_type_name(std::any::type_name::<Self>(), last) util::partial_type_name(std::any::type_name::<Self>(), last)
} }
} }

View file

@ -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<E: ?Sized + ExtensionTrait> BaseExtension for E {
fn type_name(&self) -> &'static str {
std::any::type_name::<Self>()
}
fn single_name(&self) -> &'static str {
util::partial_type_name(std::any::type_name::<Self>(), 1)
}
fn qualified_name(&self, last: u8) -> &'static str {
util::partial_type_name(std::any::type_name::<Self>(), last)
}
}

View file

@ -3,6 +3,14 @@ pub use definition::{
BaseModule, BaseModule,
ModuleTrait, ModuleTrait,
}; };
mod extension;
pub use extension::{
BaseExtension,
ExtensionTrait,
};
pub(crate) mod all; pub(crate) mod all;
pub use all::register_module; pub use all::{
extensions,
register_module
};

View file

@ -1,6 +1,6 @@
use crate::html::{Markup, html}; use crate::html::{Markup, html};
use crate::core::response::page::PageAssets; use crate::core::response::page::PageAssets;
use crate::util::partial_type_name; use crate::util;
pub use std::any::Any as AnyComponent; pub use std::any::Any as AnyComponent;
@ -9,7 +9,7 @@ pub trait BaseComponent {
fn single_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;
} }
pub trait ComponentTrait: AnyComponent + BaseComponent + Send + Sync { pub trait ComponentTrait: AnyComponent + BaseComponent + Send + Sync {
@ -52,11 +52,11 @@ impl<C: ?Sized + ComponentTrait> BaseComponent for C {
} }
fn single_name(&self) -> &'static str { fn single_name(&self) -> &'static str {
partial_type_name(std::any::type_name::<Self>(), 1) util::partial_type_name(std::any::type_name::<Self>(), 1)
} }
fn qualified_name(&self, last: usize) -> &'static str { fn qualified_name(&self, last: u8) -> &'static str {
partial_type_name(std::any::type_name::<Self>(), last) util::partial_type_name(std::any::type_name::<Self>(), last)
} }
} }

View file

@ -3,14 +3,14 @@ use crate::config::SETTINGS;
use crate::html::{Markup, html}; use crate::html::{Markup, html};
use crate::core::response::page::{ComponentTrait, Favicon, Page, PageAssets}; use crate::core::response::page::{ComponentTrait, Favicon, Page, PageAssets};
use crate::base::component::Chunck; use crate::base::component::Chunck;
use crate::util::partial_type_name; use crate::util;
pub trait BaseTheme { pub trait BaseTheme {
fn type_name(&self) -> &'static str; fn type_name(&self) -> &'static str;
fn single_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". /// Los temas deben implementar este "trait".
@ -143,10 +143,10 @@ impl<T: ?Sized + ThemeTrait> BaseTheme for T {
} }
fn single_name(&self) -> &'static str { fn single_name(&self) -> &'static str {
partial_type_name(std::any::type_name::<Self>(), 1) util::partial_type_name(std::any::type_name::<Self>(), 1)
} }
fn qualified_name(&self, last: usize) -> &'static str { fn qualified_name(&self, last: u8) -> &'static str {
partial_type_name(std::any::type_name::<Self>(), last) util::partial_type_name(std::any::type_name::<Self>(), last)
} }
} }

View file

@ -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 { if last == 0 {
return type_name; return type_name;
} }
let positions: Vec<_> = type_name.rmatch_indices("::").collect(); let positions: Vec<_> = type_name.rmatch_indices("::").collect();
let last: usize = last as usize;
if positions.len() < last { if positions.len() < last {
return type_name; return type_name;
} }