♻️ (core): Cambia HashMap x Vec en RegionComponents
This commit is contained in:
parent
7e6a9f8557
commit
74dbcde5c5
2 changed files with 49 additions and 26 deletions
|
|
@ -381,8 +381,12 @@ impl Children {
|
||||||
// **< Children HELPERS >***********************************************************************
|
// **< Children HELPERS >***********************************************************************
|
||||||
|
|
||||||
// Añade más de un componente hijo al final de la lista (en el orden recibido).
|
// Añade más de un componente hijo al final de la lista (en el orden recibido).
|
||||||
|
//
|
||||||
|
// Usa `Vec::extend()`, que reserva la capacidad necesaria de una vez a partir del `size_hint()`
|
||||||
|
// del iterador, en vez de una reasignación incremental por cada `push()`. También lo usa
|
||||||
|
// `core::theme::regions` para fusionar las fuentes de una región.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn add_many<I>(&mut self, iter: I) -> &mut Self
|
pub(crate) fn add_many<I>(&mut self, iter: I) -> &mut Self
|
||||||
where
|
where
|
||||||
I: IntoIterator<Item = Child>,
|
I: IntoIterator<Item = Child>,
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -7,16 +7,39 @@ use parking_lot::RwLock;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::{Arc, LazyLock};
|
use std::sync::{Arc, LazyLock};
|
||||||
|
|
||||||
// Mapea cada nombre de región con su lista de prototipos de componentes.
|
// Lista de prototipos de componentes por nombre de región.
|
||||||
|
//
|
||||||
|
// Utiliza Vec en lugar de HashMap. El número de regiones registradas por tema o aplicación es casi
|
||||||
|
// siempre de un dígito, así que una búsqueda lineal por igualdad de `&str` evita el coste de
|
||||||
|
// hashear la clave. Además, el trabajo para recorrer regiones vacías es mínimo.
|
||||||
//
|
//
|
||||||
// La clave es `&'static str` (lo que ya devuelve `RegionName::name()`) en lugar de `String`. No
|
// La clave es `&'static str` (lo que ya devuelve `RegionName::name()`) en lugar de `String`. No
|
||||||
// hace falta reservar en el heap una copia de un dato que ya vive de forma estática.
|
// hace falta reservar en el heap una copia de un dato que ya vive de forma estática.
|
||||||
//
|
#[derive(AutoDefault)]
|
||||||
// Se comparten como `Arc<dyn Component>`. El prototipo no se clona al registrarse ni al ensamblar
|
struct RegionComponents(Vec<(&'static str, Vec<Arc<dyn Component>>)>);
|
||||||
// la región (sólo se clona el `Arc`, barato). En cambio, sí se realiza un clonado del componente en
|
|
||||||
// `Child::render()`, cuando cada petición necesita su propia copia mutable para pasar por `setup()`
|
impl RegionComponents {
|
||||||
// desde un estado inicial limpio.
|
// Devuelve los prototipos registrados para la región indicada, si hay alguno.
|
||||||
type RegionComponents = HashMap<&'static str, Vec<Arc<dyn Component>>>;
|
fn get(&self, region_name: &str) -> Option<&Vec<Arc<dyn Component>>> {
|
||||||
|
self.0
|
||||||
|
.iter()
|
||||||
|
.find(|(name, _)| *name == region_name)
|
||||||
|
.map(|(_, protos)| protos)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Añade un prototipo a la región indicada, creando la entrada si es la primera.
|
||||||
|
//
|
||||||
|
// Se comparte como `Arc<dyn Component>`. El prototipo no se clona aquí ni al ensamblar la
|
||||||
|
// región (sólo se clona el `Arc`, barato). El único clonado real del componente ocurre en
|
||||||
|
// `Child::render()`, cuando cada petición necesita su propia copia mutable para pasar por
|
||||||
|
// `setup()` desde un estado inicial limpio.
|
||||||
|
fn push(&mut self, region_name: &'static str, proto: Arc<dyn Component>) {
|
||||||
|
match self.0.iter_mut().find(|(name, _)| *name == region_name) {
|
||||||
|
Some((_, protos)) => protos.push(proto),
|
||||||
|
None => self.0.push((region_name, vec![proto])),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Regiones globales con prototipos asociados a un tema específico.
|
// Regiones globales con prototipos asociados a un tema específico.
|
||||||
static THEME_REGIONS: LazyLock<RwLock<HashMap<UniqueId, RegionComponents>>> =
|
static THEME_REGIONS: LazyLock<RwLock<HashMap<UniqueId, RegionComponents>>> =
|
||||||
|
|
@ -24,7 +47,7 @@ static THEME_REGIONS: LazyLock<RwLock<HashMap<UniqueId, RegionComponents>>> =
|
||||||
|
|
||||||
// Regiones globales con prototipos comunes a todos los temas.
|
// Regiones globales con prototipos comunes a todos los temas.
|
||||||
static COMMON_REGIONS: LazyLock<RwLock<RegionComponents>> =
|
static COMMON_REGIONS: LazyLock<RwLock<RegionComponents>> =
|
||||||
LazyLock::new(|| RwLock::new(HashMap::new()));
|
LazyLock::new(|| RwLock::new(RegionComponents::default()));
|
||||||
|
|
||||||
// *************************************************************************************************
|
// *************************************************************************************************
|
||||||
|
|
||||||
|
|
@ -68,23 +91,25 @@ impl ChildrenInRegions {
|
||||||
|
|
||||||
// 1. Prototipos globales comunes.
|
// 1. Prototipos globales comunes.
|
||||||
if let Some(global_protos) = COMMON_REGIONS.read().get(region_name) {
|
if let Some(global_protos) = COMMON_REGIONS.read().get(region_name) {
|
||||||
for proto in global_protos {
|
result.add_many(
|
||||||
result.add(Child::from_arc(Arc::clone(proto)));
|
global_protos
|
||||||
}
|
.iter()
|
||||||
|
.map(|proto| Child::from_arc(Arc::clone(proto))),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
// 2. Componentes propios de la página: se mueven, no se clonan.
|
// 2. Componentes propios de la página: se mueven, no se clonan.
|
||||||
if let Some(page_children) = self.0.remove(region_name) {
|
if let Some(page_children) = self.0.remove(region_name) {
|
||||||
for child in page_children {
|
result.add_many(page_children);
|
||||||
result.add(child);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// 3. Prototipos del tema activo.
|
// 3. Prototipos del tema activo.
|
||||||
if let Some(theme_region) = THEME_REGIONS.read().get(&theme.type_id())
|
if let Some(theme_region) = THEME_REGIONS.read().get(&theme.type_id())
|
||||||
&& let Some(theme_protos) = theme_region.get(region_name)
|
&& let Some(theme_protos) = theme_region.get(region_name)
|
||||||
{
|
{
|
||||||
for proto in theme_protos {
|
result.add_many(
|
||||||
result.add(Child::from_arc(Arc::clone(proto)));
|
theme_protos
|
||||||
}
|
.iter()
|
||||||
|
.map(|proto| Child::from_arc(Arc::clone(proto))),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
result
|
result
|
||||||
|
|
@ -167,9 +192,7 @@ impl InRegion {
|
||||||
.write()
|
.write()
|
||||||
.entry(theme.type_id())
|
.entry(theme.type_id())
|
||||||
.or_default()
|
.or_default()
|
||||||
.entry((*region).name())
|
.push((*region).name(), proto);
|
||||||
.or_default()
|
|
||||||
.push(proto);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self
|
self
|
||||||
|
|
@ -177,10 +200,6 @@ impl InRegion {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn add_to_common(region: RegionRef, proto: Arc<dyn Component>) {
|
fn add_to_common(region: RegionRef, proto: Arc<dyn Component>) {
|
||||||
COMMON_REGIONS
|
COMMON_REGIONS.write().push(region.name(), proto);
|
||||||
.write()
|
|
||||||
.entry(region.name())
|
|
||||||
.or_default()
|
|
||||||
.push(proto);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue