♻️ (core): Simplifica Child a Arc<dyn Component>
Elimina el `RwLock<Box<dyn Component>>` interno ya que ningún punto del ciclo de renderizado tomaba el write-lock. De paso, `From<Embed<C>> for Child` pasa a una coerción de puntero sin clonar, gracias al copy-on-write que ya ofrece `Embed::get_mut()`. Los doctests en `rust,ignore` pasan a `rust,no_run`, verificados por el compilador.
This commit is contained in:
parent
65c8a788c2
commit
ce6b4d2581
1 changed files with 40 additions and 32 deletions
|
|
@ -2,8 +2,6 @@ use crate::core::component::{Component, Context};
|
||||||
use crate::html::{Markup, html};
|
use crate::html::{Markup, html};
|
||||||
use crate::{AutoDefault, UniqueId, builder_fn};
|
use crate::{AutoDefault, UniqueId, builder_fn};
|
||||||
|
|
||||||
use parking_lot::RwLock;
|
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::vec::IntoIter;
|
use std::vec::IntoIter;
|
||||||
|
|
@ -11,14 +9,19 @@ use std::vec::IntoIter;
|
||||||
// **< Child >**************************************************************************************
|
// **< Child >**************************************************************************************
|
||||||
|
|
||||||
/// Representa un componente hijo encapsulado para su uso en una lista [`Children`].
|
/// Representa un componente hijo encapsulado para su uso en una lista [`Children`].
|
||||||
|
///
|
||||||
|
/// Envuelve el componente en `Arc<dyn Component>`, compartido y de sólo lectura. Clonar un `Child`
|
||||||
|
/// sólo incrementa el contador de referencias. Para renderizar obtiene una copia propia con
|
||||||
|
/// [`ComponentClone::clone_box()`](crate::core::component::ComponentClone::clone_box), de modo que
|
||||||
|
/// el componente original nunca se modifica.
|
||||||
#[derive(AutoDefault, Clone)]
|
#[derive(AutoDefault, Clone)]
|
||||||
pub struct Child(Option<Arc<RwLock<Box<dyn Component>>>>);
|
pub struct Child(Option<Arc<dyn Component>>);
|
||||||
|
|
||||||
impl fmt::Debug for Child {
|
impl fmt::Debug for Child {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match &self.0 {
|
match &self.0 {
|
||||||
None => write!(f, "Child(None)"),
|
None => write!(f, "Child(None)"),
|
||||||
Some(c) => write!(f, "Child({})", c.read().name()),
|
Some(c) => write!(f, "Child({})", c.name()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -26,7 +29,7 @@ impl fmt::Debug for Child {
|
||||||
impl Child {
|
impl Child {
|
||||||
/// Crea un nuevo `Child` a partir de un componente.
|
/// Crea un nuevo `Child` a partir de un componente.
|
||||||
pub fn with(component: impl Component) -> Self {
|
pub fn with(component: impl Component) -> Self {
|
||||||
Child(Some(Arc::new(RwLock::new(Box::new(component)))))
|
Child(Some(Arc::new(component)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// **< Child BUILDER >**************************************************************************
|
// **< Child BUILDER >**************************************************************************
|
||||||
|
|
@ -36,7 +39,7 @@ impl Child {
|
||||||
/// Si se proporciona `Some(component)`, se encapsula como [`Child`]; y si es `None`, se limpia.
|
/// Si se proporciona `Some(component)`, se encapsula como [`Child`]; y si es `None`, se limpia.
|
||||||
#[builder_fn]
|
#[builder_fn]
|
||||||
pub fn with_component<C: Component>(mut self, component: Option<C>) -> Self {
|
pub fn with_component<C: Component>(mut self, component: Option<C>) -> Self {
|
||||||
self.0 = component.map(|c| Arc::new(RwLock::new(Box::new(c) as Box<dyn Component>)));
|
self.0 = component.map(|c| Arc::new(c) as Arc<dyn Component>);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -45,7 +48,7 @@ impl Child {
|
||||||
/// Devuelve el identificador del componente, si existe y está definido.
|
/// Devuelve el identificador del componente, si existe y está definido.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn id(&self) -> Option<String> {
|
pub fn id(&self) -> Option<String> {
|
||||||
self.0.as_ref().and_then(|c| c.read().id())
|
self.0.as_ref().and_then(|c| c.id())
|
||||||
}
|
}
|
||||||
|
|
||||||
// **< Child RENDER >***************************************************************************
|
// **< Child RENDER >***************************************************************************
|
||||||
|
|
@ -55,7 +58,7 @@ impl Child {
|
||||||
match &self.0 {
|
match &self.0 {
|
||||||
None => html! {},
|
None => html! {},
|
||||||
Some(m) => {
|
Some(m) => {
|
||||||
let mut component = m.read().clone_box();
|
let mut component = m.clone_box();
|
||||||
component.render(cx).await
|
component.render(cx).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -66,32 +69,32 @@ impl Child {
|
||||||
// Devuelve el [`UniqueId`] del tipo del componente, si el Child no está vacío.
|
// Devuelve el [`UniqueId`] del tipo del componente, si el Child no está vacío.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn type_id(&self) -> Option<UniqueId> {
|
fn type_id(&self) -> Option<UniqueId> {
|
||||||
self.0.as_ref().map(|c| c.read().type_id())
|
self.0.as_ref().map(|c| c.type_id())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C: Component + 'static> From<Embed<C>> for Child {
|
impl<C: Component + 'static> From<Embed<C>> for Child {
|
||||||
/// Convierte un [`Embed<C>`] en un [`Child`], consumiendo el componente tipado.
|
/// Convierte un [`Embed<C>`] en un [`Child`], consumiendo el componente tipado.
|
||||||
///
|
///
|
||||||
/// Útil cuando se tiene un [`Embed`] y se necesita añadirlo a una lista [`Children`]:
|
/// Útil cuando se tiene un [`Embed`] para añadir a una lista [`Children`]:
|
||||||
///
|
///
|
||||||
/// ```rust,ignore
|
/// ```rust,no_run
|
||||||
/// children.with_child(Child::from(my_embed));
|
/// # use pagetop::prelude::*;
|
||||||
/// // o equivalentemente:
|
/// let my_embed = Embed::with(Html::with(|_| html! { "Text" }));
|
||||||
/// children.with_child(my_embed.into());
|
/// let children = Children::new().with_child(Child::from(my_embed));
|
||||||
|
///
|
||||||
|
/// // De forma equivalente se puede usar la conversión implícita hacia `Child`:
|
||||||
|
/// let my_embed = Embed::with(Html::with(|_| html! { "Text" }));
|
||||||
|
/// let child: Child = my_embed.into();
|
||||||
|
/// let children = children.with_child(child);
|
||||||
/// ```
|
/// ```
|
||||||
fn from(embed: Embed<C>) -> Self {
|
fn from(embed: Embed<C>) -> Self {
|
||||||
match embed.0 {
|
Child(embed.0.map(|arc| arc as Arc<dyn Component>))
|
||||||
None => Child(None),
|
|
||||||
Some(arc) => Child(Some(Arc::new(RwLock::new(match Arc::try_unwrap(arc) {
|
|
||||||
Ok(c) => Box::new(c) as Box<dyn Component>,
|
|
||||||
Err(arc) => arc.clone_box(),
|
|
||||||
})))),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Component + 'static> From<T> for Child {
|
impl<T: Component + 'static> From<T> for Child {
|
||||||
|
/// Convierte cualquier componente en un [`Child`], equivalente a [`Child::with()`].
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(component: T) -> Self {
|
fn from(component: T) -> Self {
|
||||||
Child::with(component)
|
Child::with(component)
|
||||||
|
|
@ -270,12 +273,13 @@ pub enum ChildOp {
|
||||||
/// Gracias a esto, [`with_child`](Self::with_child) acepta un componente directamente o cualquier
|
/// Gracias a esto, [`with_child`](Self::with_child) acepta un componente directamente o cualquier
|
||||||
/// variante de [`ChildOp`]:
|
/// variante de [`ChildOp`]:
|
||||||
///
|
///
|
||||||
/// ```rust,ignore
|
/// ```rust,no_run
|
||||||
|
/// # use pagetop::prelude::*;
|
||||||
/// // Añadir al final de la lista (implícito):
|
/// // Añadir al final de la lista (implícito):
|
||||||
/// children.with_child(MiComponente::new());
|
/// let children = Children::new().with_child(Html::new());
|
||||||
///
|
///
|
||||||
/// // Operación explícita:
|
/// // Operación explícita:
|
||||||
/// children.with_child(ChildOp::Prepend(MiComponente::new().into()));
|
/// let children = children.with_child(ChildOp::Prepend(Html::new().into()));
|
||||||
/// ```
|
/// ```
|
||||||
#[derive(AutoDefault, Clone, Debug)]
|
#[derive(AutoDefault, Clone, Debug)]
|
||||||
pub struct Children(Vec<Child>);
|
pub struct Children(Vec<Child>);
|
||||||
|
|
@ -458,8 +462,9 @@ impl IntoIterator for Children {
|
||||||
///
|
///
|
||||||
/// # Ejemplo
|
/// # Ejemplo
|
||||||
///
|
///
|
||||||
/// ```rust,ignore
|
/// ```rust,no_run
|
||||||
/// let children = Children::new().with_child(child1).with_child(child2);
|
/// # use pagetop::prelude::*;
|
||||||
|
/// let children = Children::new().with_child(Html::new()).with_child(Html::new());
|
||||||
/// for child in children {
|
/// for child in children {
|
||||||
/// println!("{:?}", child.id());
|
/// println!("{:?}", child.id());
|
||||||
/// }
|
/// }
|
||||||
|
|
@ -477,8 +482,9 @@ impl<'a> IntoIterator for &'a Children {
|
||||||
///
|
///
|
||||||
/// # Ejemplo
|
/// # Ejemplo
|
||||||
///
|
///
|
||||||
/// ```rust,ignore
|
/// ```rust,no_run
|
||||||
/// let children = Children::new().with_child(child1).with_child(child2);
|
/// # use pagetop::prelude::*;
|
||||||
|
/// let children = Children::new().with_child(Html::new()).with_child(Html::new());
|
||||||
/// for child in &children {
|
/// for child in &children {
|
||||||
/// println!("{:?}", child.id());
|
/// println!("{:?}", child.id());
|
||||||
/// }
|
/// }
|
||||||
|
|
@ -496,10 +502,12 @@ impl<'a> IntoIterator for &'a mut Children {
|
||||||
///
|
///
|
||||||
/// # Ejemplo
|
/// # Ejemplo
|
||||||
///
|
///
|
||||||
/// ```rust,ignore
|
/// ```rust,no_run
|
||||||
/// let mut children = Children::new().with_child(child1).with_child(child2);
|
/// # use pagetop::prelude::*;
|
||||||
|
/// async fn render_all(mut children: Children, context: &mut Context) {
|
||||||
/// for child in &mut children {
|
/// for child in &mut children {
|
||||||
/// child.render(&mut context).await;
|
/// child.render(context).await;
|
||||||
|
/// }
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
fn into_iter(self) -> Self::IntoIter {
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue