✨ New type query function using TypeInfo
This commit is contained in:
parent
4b1e34487d
commit
5e457eed3d
8 changed files with 104 additions and 46 deletions
10
src/core.rs
10
src/core.rs
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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> {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
20
src/db.rs
20
src/db.rs
|
|
@ -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 {
|
||||
() => {
|
||||
|
|
|
|||
|
|
@ -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};
|
||||
|
|
|
|||
91
src/util.rs
91
src/util.rs
|
|
@ -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>,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue