✨ 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.
|
//! Key types and functions for creating actions, components, packages, and themes.
|
||||||
|
|
||||||
use crate::util;
|
use crate::util::TypeInfo;
|
||||||
|
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
|
|
||||||
|
|
@ -8,7 +8,7 @@ use std::any::Any;
|
||||||
pub trait AnyBase: Any {
|
pub trait AnyBase: Any {
|
||||||
fn type_name(&self) -> &'static str;
|
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;
|
fn as_any_ref(&self) -> &dyn Any;
|
||||||
|
|
||||||
|
|
@ -18,12 +18,12 @@ pub trait AnyBase: Any {
|
||||||
impl<T: Any> AnyBase for T {
|
impl<T: Any> AnyBase for T {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn type_name(&self) -> &'static str {
|
fn type_name(&self) -> &'static str {
|
||||||
std::any::type_name::<T>()
|
TypeInfo::FullName.of::<T>()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn single_name(&self) -> &'static str {
|
fn short_name(&self) -> &'static str {
|
||||||
util::single_type_name::<T>()
|
TypeInfo::ShortName.of::<T>()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,14 @@
|
||||||
use crate::base::component::add_base_assets;
|
use crate::base::component::add_base_assets;
|
||||||
|
use crate::concat_string;
|
||||||
use crate::core::component::AnyOp;
|
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::core::theme::{ComponentsInRegions, ThemeRef};
|
||||||
use crate::html::{html, Markup};
|
use crate::html::{html, Markup};
|
||||||
use crate::html::{Assets, HeadScript, HeadStyles, JavaScript, StyleSheet};
|
use crate::html::{Assets, HeadScript, HeadStyles, JavaScript, StyleSheet};
|
||||||
use crate::html::{ClassesOp, OptionClasses, OptionId};
|
use crate::html::{ClassesOp, OptionClasses, OptionId};
|
||||||
use crate::locale::{LanguageIdentifier, LANGID_DEFAULT};
|
use crate::locale::{LanguageIdentifier, LANGID_DEFAULT};
|
||||||
use crate::service::HttpRequest;
|
use crate::service::HttpRequest;
|
||||||
use crate::{concat_string, util};
|
use crate::util::TypeInfo;
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
@ -78,7 +79,7 @@ impl Context {
|
||||||
self.langid = langid;
|
self.langid = langid;
|
||||||
}
|
}
|
||||||
AssetsOp::Theme(theme_name) => {
|
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) => {
|
AssetsOp::Layout(layout) => {
|
||||||
self.layout = layout;
|
self.layout = layout;
|
||||||
|
|
@ -199,7 +200,8 @@ impl Context {
|
||||||
match id {
|
match id {
|
||||||
Some(id) => id,
|
Some(id) => id,
|
||||||
None => {
|
None => {
|
||||||
let prefix = util::single_type_name::<T>()
|
let prefix = TypeInfo::ShortName
|
||||||
|
.of::<T>()
|
||||||
.trim()
|
.trim()
|
||||||
.replace(' ', "_")
|
.replace(' ', "_")
|
||||||
.to_lowercase();
|
.to_lowercase();
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,8 @@ use crate::base::action;
|
||||||
use crate::core::component::Context;
|
use crate::core::component::Context;
|
||||||
use crate::core::AnyBase;
|
use crate::core::AnyBase;
|
||||||
use crate::html::{html, Markup, PrepareMarkup};
|
use crate::html::{html, Markup, PrepareMarkup};
|
||||||
use crate::{util, Weight};
|
use crate::util::TypeInfo;
|
||||||
|
use crate::Weight;
|
||||||
|
|
||||||
pub trait ComponentBase {
|
pub trait ComponentBase {
|
||||||
fn render(&mut self, cx: &mut Context) -> Markup;
|
fn render(&mut self, cx: &mut Context) -> Markup;
|
||||||
|
|
@ -13,8 +14,8 @@ pub trait ComponentTrait: AnyBase + ComponentBase + Send + Sync {
|
||||||
where
|
where
|
||||||
Self: Sized;
|
Self: Sized;
|
||||||
|
|
||||||
fn name(&self) -> String {
|
fn name(&self) -> &'static str {
|
||||||
util::single_type_name::<Self>().to_owned()
|
TypeInfo::ShortName.of::<Self>()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn description(&self) -> Option<String> {
|
fn description(&self) -> Option<String> {
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ pub type PackageRef = &'static dyn PackageTrait;
|
||||||
/// Los paquetes deben implementar este *trait*.
|
/// Los paquetes deben implementar este *trait*.
|
||||||
pub trait PackageTrait: AnyBase + Send + Sync {
|
pub trait PackageTrait: AnyBase + Send + Sync {
|
||||||
fn name(&self) -> L10n {
|
fn name(&self) -> L10n {
|
||||||
L10n::n(self.single_name())
|
L10n::n(self.short_name())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn description(&self) -> L10n {
|
fn description(&self) -> L10n {
|
||||||
|
|
|
||||||
|
|
@ -11,20 +11,20 @@ pub static THEMES: LazyStatic<RwLock<Vec<ThemeRef>>> = LazyStatic::new(|| RwLock
|
||||||
// DEFAULT THEME ***********************************************************************************
|
// DEFAULT THEME ***********************************************************************************
|
||||||
|
|
||||||
pub static THEME_DEFAULT: LazyStatic<ThemeRef> =
|
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,
|
Some(theme) => theme,
|
||||||
None => &crate::base::theme::Inception,
|
None => &crate::base::theme::Inception,
|
||||||
});
|
});
|
||||||
|
|
||||||
// THEME BY NAME ***********************************************************************************
|
// THEME BY NAME ***********************************************************************************
|
||||||
|
|
||||||
pub fn theme_by_single_name(single_name: &str) -> Option<ThemeRef> {
|
pub fn theme_by_short_name(short_name: &str) -> Option<ThemeRef> {
|
||||||
let single_name = single_name.to_lowercase();
|
let short_name = short_name.to_lowercase();
|
||||||
match THEMES
|
match THEMES
|
||||||
.read()
|
.read()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.iter()
|
.iter()
|
||||||
.find(|t| t.single_name().to_lowercase() == single_name)
|
.find(|t| t.short_name().to_lowercase() == short_name)
|
||||||
{
|
{
|
||||||
Some(theme) => Some(*theme),
|
Some(theme) => Some(*theme),
|
||||||
_ => None,
|
_ => None,
|
||||||
|
|
|
||||||
16
src/db.rs
16
src/db.rs
|
|
@ -1,5 +1,6 @@
|
||||||
//! Database access.
|
//! Database access.
|
||||||
|
|
||||||
|
use crate::util::TypeInfo;
|
||||||
use crate::{config, trace, LazyStatic};
|
use crate::{config, trace, LazyStatic};
|
||||||
|
|
||||||
pub use url::Url as DbUri;
|
pub use url::Url as DbUri;
|
||||||
|
|
@ -148,20 +149,13 @@ pub async fn exec_raw(stmt: String) -> Result<ExecResult, DbErr> {
|
||||||
mod migration;
|
mod migration;
|
||||||
pub use migration::prelude::*;
|
pub use migration::prelude::*;
|
||||||
|
|
||||||
pub type MigrationItem = Box<dyn MigrationTrait>;
|
impl<M: MigrationTrait> MigrationName for M {
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! new_migration {
|
|
||||||
( $migration:ident ) => {
|
|
||||||
pub struct $migration;
|
|
||||||
|
|
||||||
impl MigrationName for $migration {
|
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
$crate::util::partial_type_name(module_path!(), 1)
|
TypeInfo::NameTo(-2).of::<M>()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
}
|
pub type MigrationItem = Box<dyn MigrationTrait>;
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! migrations {
|
macro_rules! migrations {
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ pub use crate::locale::*;
|
||||||
pub use crate::datetime::*;
|
pub use crate::datetime::*;
|
||||||
|
|
||||||
#[cfg(feature = "database")]
|
#[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;
|
||||||
pub use crate::service::{HttpMessage, HttpRequest};
|
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::io;
|
||||||
use std::path::PathBuf;
|
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.
|
// 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(
|
pub fn absolute_dir(
|
||||||
root_path: impl Into<String>,
|
root_path: impl Into<String>,
|
||||||
relative_path: impl Into<String>,
|
relative_path: impl Into<String>,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue