New type query function using TypeInfo

This commit is contained in:
Manuel Cillero 2024-04-12 21:45:13 +02:00
parent 4b1e34487d
commit 5e457eed3d
8 changed files with 104 additions and 46 deletions

View file

@ -1,6 +1,6 @@
//! Key types and functions for creating actions, components, packages, and themes.
use crate::util;
use crate::util::TypeInfo;
use std::any::Any;
@ -8,7 +8,7 @@ use std::any::Any;
pub trait AnyBase: Any {
fn type_name(&self) -> &'static str;
fn single_name(&self) -> &'static str;
fn short_name(&self) -> &'static str;
fn as_any_ref(&self) -> &dyn Any;
@ -18,12 +18,12 @@ pub trait AnyBase: Any {
impl<T: Any> AnyBase for T {
#[inline(always)]
fn type_name(&self) -> &'static str {
std::any::type_name::<T>()
TypeInfo::FullName.of::<T>()
}
#[inline(always)]
fn single_name(&self) -> &'static str {
util::single_type_name::<T>()
fn short_name(&self) -> &'static str {
TypeInfo::ShortName.of::<T>()
}
#[inline(always)]

View file

@ -1,13 +1,14 @@
use crate::base::component::add_base_assets;
use crate::concat_string;
use crate::core::component::AnyOp;
use crate::core::theme::all::{theme_by_single_name, THEME_DEFAULT};
use crate::core::theme::all::{theme_by_short_name, THEME_DEFAULT};
use crate::core::theme::{ComponentsInRegions, ThemeRef};
use crate::html::{html, Markup};
use crate::html::{Assets, HeadScript, HeadStyles, JavaScript, StyleSheet};
use crate::html::{ClassesOp, OptionClasses, OptionId};
use crate::locale::{LanguageIdentifier, LANGID_DEFAULT};
use crate::service::HttpRequest;
use crate::{concat_string, util};
use crate::util::TypeInfo;
use std::collections::HashMap;
use std::str::FromStr;
@ -78,7 +79,7 @@ impl Context {
self.langid = langid;
}
AssetsOp::Theme(theme_name) => {
self.theme = theme_by_single_name(theme_name).unwrap_or(*THEME_DEFAULT);
self.theme = theme_by_short_name(theme_name).unwrap_or(*THEME_DEFAULT);
}
AssetsOp::Layout(layout) => {
self.layout = layout;
@ -199,7 +200,8 @@ impl Context {
match id {
Some(id) => id,
None => {
let prefix = util::single_type_name::<T>()
let prefix = TypeInfo::ShortName
.of::<T>()
.trim()
.replace(' ', "_")
.to_lowercase();

View file

@ -2,7 +2,8 @@ use crate::base::action;
use crate::core::component::Context;
use crate::core::AnyBase;
use crate::html::{html, Markup, PrepareMarkup};
use crate::{util, Weight};
use crate::util::TypeInfo;
use crate::Weight;
pub trait ComponentBase {
fn render(&mut self, cx: &mut Context) -> Markup;
@ -13,8 +14,8 @@ pub trait ComponentTrait: AnyBase + ComponentBase + Send + Sync {
where
Self: Sized;
fn name(&self) -> String {
util::single_type_name::<Self>().to_owned()
fn name(&self) -> &'static str {
TypeInfo::ShortName.of::<Self>()
}
fn description(&self) -> Option<String> {

View file

@ -12,7 +12,7 @@ pub type PackageRef = &'static dyn PackageTrait;
/// Los paquetes deben implementar este *trait*.
pub trait PackageTrait: AnyBase + Send + Sync {
fn name(&self) -> L10n {
L10n::n(self.single_name())
L10n::n(self.short_name())
}
fn description(&self) -> L10n {

View file

@ -11,20 +11,20 @@ pub static THEMES: LazyStatic<RwLock<Vec<ThemeRef>>> = LazyStatic::new(|| RwLock
// DEFAULT THEME ***********************************************************************************
pub static THEME_DEFAULT: LazyStatic<ThemeRef> =
LazyStatic::new(|| match theme_by_single_name(&config::SETTINGS.app.theme) {
LazyStatic::new(|| match theme_by_short_name(&config::SETTINGS.app.theme) {
Some(theme) => theme,
None => &crate::base::theme::Inception,
});
// THEME BY NAME ***********************************************************************************
pub fn theme_by_single_name(single_name: &str) -> Option<ThemeRef> {
let single_name = single_name.to_lowercase();
pub fn theme_by_short_name(short_name: &str) -> Option<ThemeRef> {
let short_name = short_name.to_lowercase();
match THEMES
.read()
.unwrap()
.iter()
.find(|t| t.single_name().to_lowercase() == single_name)
.find(|t| t.short_name().to_lowercase() == short_name)
{
Some(theme) => Some(*theme),
_ => None,

View file

@ -1,5 +1,6 @@
//! Database access.
use crate::util::TypeInfo;
use crate::{config, trace, LazyStatic};
pub use url::Url as DbUri;
@ -148,21 +149,14 @@ pub async fn exec_raw(stmt: String) -> Result<ExecResult, DbErr> {
mod migration;
pub use migration::prelude::*;
pub type MigrationItem = Box<dyn MigrationTrait>;
#[macro_export]
macro_rules! new_migration {
( $migration:ident ) => {
pub struct $migration;
impl MigrationName for $migration {
fn name(&self) -> &str {
$crate::util::partial_type_name(module_path!(), 1)
}
}
};
impl<M: MigrationTrait> MigrationName for M {
fn name(&self) -> &str {
TypeInfo::NameTo(-2).of::<M>()
}
}
pub type MigrationItem = Box<dyn MigrationTrait>;
#[macro_export]
macro_rules! migrations {
() => {

View file

@ -37,7 +37,7 @@ pub use crate::locale::*;
pub use crate::datetime::*;
#[cfg(feature = "database")]
pub use crate::{db, db::*, migrations, new_migration};
pub use crate::{db, db::*, migrations};
pub use crate::service;
pub use crate::service::{HttpMessage, HttpRequest};

View file

@ -5,25 +5,86 @@ use crate::trace;
use std::io;
use std::path::PathBuf;
pub enum TypeInfo {
FullName,
ShortName,
NameFrom(isize),
NameTo(isize),
PartialName(isize, isize),
}
impl TypeInfo {
pub fn of<T: ?Sized>(&self) -> &'static str {
let type_name = std::any::type_name::<T>();
match self {
TypeInfo::FullName => type_name,
TypeInfo::ShortName => Self::partial(type_name, -1, None),
TypeInfo::NameFrom(start) => Self::partial(type_name, *start, None),
TypeInfo::NameTo(end) => Self::partial(type_name, 0, Some(*end)),
TypeInfo::PartialName(start, end) => Self::partial(type_name, *start, Some(*end)),
}
}
fn partial(type_name: &'static str, start: isize, end: Option<isize>) -> &'static str {
let maxlen = type_name.len();
let mut segments = Vec::new();
let mut segment_start = 0; // Start position of the current segment.
let mut angle_brackets = 0; // Counter for tracking '<' and '>'.
let mut previous_char = '\0'; // Initializes to a null character, no previous character.
for (idx, c) in type_name.char_indices() {
match c {
':' if angle_brackets == 0 => {
if previous_char == ':' {
if segment_start < idx - 1 {
segments.push((segment_start, idx - 1)); // Do not include last '::'.
}
segment_start = idx + 1; // Next segment starts after '::'.
}
}
'<' => angle_brackets += 1,
'>' => angle_brackets -= 1,
_ => {}
}
previous_char = c;
}
// Include the last segment if there's any.
if segment_start < maxlen {
segments.push((segment_start, maxlen));
}
// Calculates the start position.
let start_pos = segments
.get(if start >= 0 {
start as usize
} else {
segments.len() - start.abs() as usize
})
.map_or(0, |&(s, _)| s);
// Calculates the end position.
let end_pos = segments
.get(if let Some(end) = end {
if end >= 0 {
end as usize
} else {
segments.len() - end.abs() as usize
}
} else {
segments.len() - 1
})
.map_or(maxlen, |&(_, e)| e);
// Returns the partial string based on the calculated positions.
&type_name[start_pos..end_pos]
}
}
// *************************************************************************************************
// FUNCTIONS HELPERS.
// *************************************************************************************************
pub fn partial_type_name(type_name: &'static str, last: usize) -> &'static str {
if last == 0 {
return type_name;
}
let positions: Vec<_> = type_name.rmatch_indices("::").collect();
if positions.len() < last {
return type_name;
}
&type_name[(positions[last - 1].0 + 2)..]
}
pub fn single_type_name<T: ?Sized>() -> &'static str {
partial_type_name(std::any::type_name::<T>(), 1)
}
pub fn absolute_dir(
root_path: impl Into<String>,
relative_path: impl Into<String>,