From ce6b4d2581f0ff70840fa7caa248c48f15d5096b Mon Sep 17 00:00:00 2001 From: Manuel Cillero Date: Sun, 26 Jul 2026 11:30:16 +0200 Subject: [PATCH] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20(core):=20Simplifica=20Chi?= =?UTF-8?q?ld=20a=20Arc?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Elimina el `RwLock>` interno ya que ningún punto del ciclo de renderizado tomaba el write-lock. De paso, `From> 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. --- src/core/component/children.rs | 72 +++++++++++++++++++--------------- 1 file changed, 40 insertions(+), 32 deletions(-) diff --git a/src/core/component/children.rs b/src/core/component/children.rs index cadcb05c..b76a6258 100644 --- a/src/core/component/children.rs +++ b/src/core/component/children.rs @@ -2,8 +2,6 @@ use crate::core::component::{Component, Context}; use crate::html::{Markup, html}; use crate::{AutoDefault, UniqueId, builder_fn}; -use parking_lot::RwLock; - use std::fmt; use std::sync::Arc; use std::vec::IntoIter; @@ -11,14 +9,19 @@ use std::vec::IntoIter; // **< Child >************************************************************************************** /// Representa un componente hijo encapsulado para su uso en una lista [`Children`]. +/// +/// Envuelve el componente en `Arc`, 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)] -pub struct Child(Option>>>); +pub struct Child(Option>); impl fmt::Debug for Child { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match &self.0 { 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 { /// Crea un nuevo `Child` a partir de un componente. pub fn with(component: impl Component) -> Self { - Child(Some(Arc::new(RwLock::new(Box::new(component))))) + Child(Some(Arc::new(component))) } // **< Child BUILDER >************************************************************************** @@ -36,7 +39,7 @@ impl Child { /// Si se proporciona `Some(component)`, se encapsula como [`Child`]; y si es `None`, se limpia. #[builder_fn] pub fn with_component(mut self, component: Option) -> Self { - self.0 = component.map(|c| Arc::new(RwLock::new(Box::new(c) as Box))); + self.0 = component.map(|c| Arc::new(c) as Arc); self } @@ -45,7 +48,7 @@ impl Child { /// Devuelve el identificador del componente, si existe y está definido. #[inline] pub fn id(&self) -> Option { - self.0.as_ref().and_then(|c| c.read().id()) + self.0.as_ref().and_then(|c| c.id()) } // **< Child RENDER >*************************************************************************** @@ -55,7 +58,7 @@ impl Child { match &self.0 { None => html! {}, Some(m) => { - let mut component = m.read().clone_box(); + let mut component = m.clone_box(); component.render(cx).await } } @@ -66,32 +69,32 @@ impl Child { // Devuelve el [`UniqueId`] del tipo del componente, si el Child no está vacío. #[inline] fn type_id(&self) -> Option { - self.0.as_ref().map(|c| c.read().type_id()) + self.0.as_ref().map(|c| c.type_id()) } } impl From> for Child { /// Convierte un [`Embed`] 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 - /// children.with_child(Child::from(my_embed)); - /// // o equivalentemente: - /// children.with_child(my_embed.into()); + /// ```rust,no_run + /// # use pagetop::prelude::*; + /// let my_embed = Embed::with(Html::with(|_| html! { "Text" })); + /// 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) -> Self { - match embed.0 { - None => Child(None), - Some(arc) => Child(Some(Arc::new(RwLock::new(match Arc::try_unwrap(arc) { - Ok(c) => Box::new(c) as Box, - Err(arc) => arc.clone_box(), - })))), - } + Child(embed.0.map(|arc| arc as Arc)) } } impl From for Child { + /// Convierte cualquier componente en un [`Child`], equivalente a [`Child::with()`]. #[inline] fn from(component: T) -> Self { Child::with(component) @@ -270,12 +273,13 @@ pub enum ChildOp { /// Gracias a esto, [`with_child`](Self::with_child) acepta un componente directamente o cualquier /// variante de [`ChildOp`]: /// -/// ```rust,ignore +/// ```rust,no_run +/// # use pagetop::prelude::*; /// // 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: -/// children.with_child(ChildOp::Prepend(MiComponente::new().into())); +/// let children = children.with_child(ChildOp::Prepend(Html::new().into())); /// ``` #[derive(AutoDefault, Clone, Debug)] pub struct Children(Vec); @@ -458,8 +462,9 @@ impl IntoIterator for Children { /// /// # Ejemplo /// - /// ```rust,ignore - /// let children = Children::new().with_child(child1).with_child(child2); + /// ```rust,no_run + /// # use pagetop::prelude::*; + /// let children = Children::new().with_child(Html::new()).with_child(Html::new()); /// for child in children { /// println!("{:?}", child.id()); /// } @@ -477,8 +482,9 @@ impl<'a> IntoIterator for &'a Children { /// /// # Ejemplo /// - /// ```rust,ignore - /// let children = Children::new().with_child(child1).with_child(child2); + /// ```rust,no_run + /// # use pagetop::prelude::*; + /// let children = Children::new().with_child(Html::new()).with_child(Html::new()); /// for child in &children { /// println!("{:?}", child.id()); /// } @@ -496,10 +502,12 @@ impl<'a> IntoIterator for &'a mut Children { /// /// # Ejemplo /// - /// ```rust,ignore - /// let mut children = Children::new().with_child(child1).with_child(child2); - /// for child in &mut children { - /// child.render(&mut context).await; + /// ```rust,no_run + /// # use pagetop::prelude::*; + /// async fn render_all(mut children: Children, context: &mut Context) { + /// for child in &mut children { + /// child.render(context).await; + /// } /// } /// ``` fn into_iter(self) -> Self::IntoIter {