From fd1187fefd5926b9ecfb5dfec72f5b354eaf3896 Mon Sep 17 00:00:00 2001 From: Cecile Tonglet Date: Sat, 30 Sep 2023 12:15:31 +0200 Subject: [PATCH 01/28] Make VNode cheap to clone --- .../yew-macro/src/html_tree/html_element.rs | 2 +- packages/yew/src/html/conversion/to_html.rs | 2 +- packages/yew/src/virtual_dom/listeners.rs | 3 +++ packages/yew/src/virtual_dom/mod.rs | 19 ++++++------- packages/yew/src/virtual_dom/vlist.rs | 3 +++ packages/yew/src/virtual_dom/vnode.rs | 19 +++++++------ packages/yew/src/virtual_dom/vportal.rs | 5 +++- packages/yew/src/virtual_dom/vraw.rs | 3 +++ packages/yew/src/virtual_dom/vsuspense.rs | 3 +++ packages/yew/src/virtual_dom/vtag.rs | 27 ++++++++++++++----- packages/yew/src/virtual_dom/vtext.rs | 3 +++ 11 files changed, 62 insertions(+), 27 deletions(-) diff --git a/packages/yew-macro/src/html_tree/html_element.rs b/packages/yew-macro/src/html_tree/html_element.rs index 0124dd0c0d7..93ce729f97c 100644 --- a/packages/yew-macro/src/html_tree/html_element.rs +++ b/packages/yew-macro/src/html_tree/html_element.rs @@ -359,7 +359,7 @@ impl ToTokens for HtmlElement { quote! { ::std::convert::Into::<::yew::virtual_dom::VNode>::into( ::yew::virtual_dom::VTag::__new_other( - ::std::borrow::Cow::<'static, ::std::primitive::str>::Borrowed(#name), + ::yew::virtual_dom::AttrValue::from(#name), #node_ref, #key, #attributes, diff --git a/packages/yew/src/html/conversion/to_html.rs b/packages/yew/src/html/conversion/to_html.rs index c7d3eeaa57b..2fba2d17b95 100644 --- a/packages/yew/src/html/conversion/to_html.rs +++ b/packages/yew/src/html/conversion/to_html.rs @@ -132,7 +132,7 @@ where #[inline(always)] fn into_html(self) -> Html { - VNode::VComp(self.into()) + VNode::VComp(Rc::new(self.into())) } } diff --git a/packages/yew/src/virtual_dom/listeners.rs b/packages/yew/src/virtual_dom/listeners.rs index caa0943d599..7008e79b00f 100644 --- a/packages/yew/src/virtual_dom/listeners.rs +++ b/packages/yew/src/virtual_dom/listeners.rs @@ -1,3 +1,4 @@ +use crate::html::ImplicitClone; use std::rc::Rc; /// The [Listener] trait is an universal implementation of an event listener @@ -168,6 +169,8 @@ pub enum Listeners { Pending(Box<[Option>]>), } +impl ImplicitClone for Listeners {} + impl PartialEq for Listeners { fn eq(&self, rhs: &Self) -> bool { use Listeners::*; diff --git a/packages/yew/src/virtual_dom/mod.rs b/packages/yew/src/virtual_dom/mod.rs index 940c46021f9..6ede1e6e074 100644 --- a/packages/yew/src/virtual_dom/mod.rs +++ b/packages/yew/src/virtual_dom/mod.rs @@ -22,6 +22,7 @@ pub mod vtag; pub mod vtext; use std::hint::unreachable_unchecked; +use std::rc::Rc; use indexmap::IndexMap; @@ -204,7 +205,7 @@ pub enum Attributes { /// IndexMap is used to provide runtime attribute deduplication in cases where the html! macro /// was not used to guarantee it. - IndexMap(IndexMap), + IndexMap(Rc>), } impl Attributes { @@ -233,7 +234,7 @@ impl Attributes { macro_rules! unpack { () => { match self { - Self::IndexMap(m) => m, + Self::IndexMap(m) => Rc::make_mut(m), // SAFETY: unreachable because we set self to the `IndexMap` variant above. _ => unsafe { unreachable_unchecked() }, } @@ -241,23 +242,23 @@ impl Attributes { } match self { - Self::IndexMap(m) => m, + Self::IndexMap(m) => Rc::make_mut(m), Self::Static(arr) => { - *self = Self::IndexMap( + *self = Self::IndexMap(Rc::new( arr.iter() .map(|(k, v, ty)| ((*k).into(), ((*v).into(), *ty))) .collect(), - ); + )); unpack!() } Self::Dynamic { keys, values } => { - *self = Self::IndexMap( + *self = Self::IndexMap(Rc::new( std::mem::take(values) .iter_mut() .zip(keys.iter()) .filter_map(|(v, k)| v.take().map(|v| (AttrValue::from(*k), v))) .collect(), - ); + )); unpack!() } } @@ -270,7 +271,7 @@ impl From> for Attributes { .into_iter() .map(|(k, v)| (k, (v, ApplyAttributeAs::Attribute))) .collect(); - Self::IndexMap(v) + Self::IndexMap(Rc::new(v)) } } @@ -280,7 +281,7 @@ impl From> for Attributes { .into_iter() .map(|(k, v)| (AttrValue::Static(k), (v, ApplyAttributeAs::Attribute))) .collect(); - Self::IndexMap(v) + Self::IndexMap(Rc::new(v)) } } diff --git a/packages/yew/src/virtual_dom/vlist.rs b/packages/yew/src/virtual_dom/vlist.rs index cd9459497f1..62dc5b14e0a 100644 --- a/packages/yew/src/virtual_dom/vlist.rs +++ b/packages/yew/src/virtual_dom/vlist.rs @@ -3,6 +3,7 @@ use std::ops::{Deref, DerefMut}; use std::rc::Rc; use super::{Key, VNode}; +use crate::html::ImplicitClone; #[derive(Clone, Copy, Debug, PartialEq)] enum FullyKeyedState { @@ -23,6 +24,8 @@ pub struct VList { pub key: Option, } +impl ImplicitClone for VList {} + impl PartialEq for VList { fn eq(&self, other: &Self) -> bool { self.key == other.key && self.children == other.children diff --git a/packages/yew/src/virtual_dom/vnode.rs b/packages/yew/src/virtual_dom/vnode.rs index 943081c2f3e..00fd8d25088 100644 --- a/packages/yew/src/virtual_dom/vnode.rs +++ b/packages/yew/src/virtual_dom/vnode.rs @@ -2,12 +2,13 @@ use std::cmp::PartialEq; use std::iter::FromIterator; +use std::rc::Rc; use std::{fmt, mem}; use web_sys::Node; use super::{Key, VChild, VComp, VList, VPortal, VSuspense, VTag, VText}; -use crate::html::BaseComponent; +use crate::html::{BaseComponent, ImplicitClone}; use crate::virtual_dom::VRaw; use crate::AttrValue; @@ -16,11 +17,11 @@ use crate::AttrValue; #[must_use = "html does not do anything unless returned to Yew for rendering."] pub enum VNode { /// A bind between `VTag` and `Element`. - VTag(Box), + VTag(Rc), /// A bind between `VText` and `TextNode`. VText(VText), /// A bind between `VComp` and `Element`. - VComp(VComp), + VComp(Rc), /// A holder for a list of other nodes. VList(VList), /// A portal to another part of the document @@ -28,13 +29,15 @@ pub enum VNode { /// A holder for any `Node` (necessary for replacing node). VRef(Node), /// A suspendible document fragment. - VSuspense(VSuspense), + VSuspense(Rc), /// A raw HTML string, represented by [`AttrValue`](crate::AttrValue). /// /// Also see: [`VNode::from_html_unchecked`] VRaw(VRaw), } +impl ImplicitClone for VNode {} + impl VNode { pub fn key(&self) -> Option<&Key> { match self { @@ -126,21 +129,21 @@ impl From for VNode { impl From for VNode { #[inline] fn from(vtag: VTag) -> Self { - VNode::VTag(Box::new(vtag)) + VNode::VTag(Rc::new(vtag)) } } impl From for VNode { #[inline] fn from(vcomp: VComp) -> Self { - VNode::VComp(vcomp) + VNode::VComp(Rc::new(vcomp)) } } impl From for VNode { #[inline] fn from(vsuspense: VSuspense) -> Self { - VNode::VSuspense(vsuspense) + VNode::VSuspense(Rc::new(vsuspense)) } } @@ -156,7 +159,7 @@ where COMP: BaseComponent, { fn from(vchild: VChild) -> Self { - VNode::VComp(VComp::from(vchild)) + VNode::VComp(Rc::new(VComp::from(vchild))) } } diff --git a/packages/yew/src/virtual_dom/vportal.rs b/packages/yew/src/virtual_dom/vportal.rs index b0b7b301f5a..d9472d9e696 100644 --- a/packages/yew/src/virtual_dom/vportal.rs +++ b/packages/yew/src/virtual_dom/vportal.rs @@ -3,17 +3,20 @@ use web_sys::{Element, Node}; use super::VNode; +use crate::html::ImplicitClone; #[derive(Debug, Clone, PartialEq)] pub struct VPortal { /// The element under which the content is inserted. pub host: Element, - /// The next sibling after the inserted content. Most be a child of `host`. + /// The next sibling after the inserted content. Must be a child of `host`. pub inner_sibling: Option, /// The inserted node pub node: Box, } +impl ImplicitClone for VPortal {} + impl VPortal { /// Creates a [VPortal] rendering `content` in the DOM hierarchy under `host`. pub fn new(content: VNode, host: Element) -> Self { diff --git a/packages/yew/src/virtual_dom/vraw.rs b/packages/yew/src/virtual_dom/vraw.rs index 366e5248f00..9c8e7a3c46a 100644 --- a/packages/yew/src/virtual_dom/vraw.rs +++ b/packages/yew/src/virtual_dom/vraw.rs @@ -1,3 +1,4 @@ +use crate::html::ImplicitClone; use crate::AttrValue; /// A raw HTML string to be used in VDOM. @@ -6,6 +7,8 @@ pub struct VRaw { pub html: AttrValue, } +impl ImplicitClone for VRaw {} + impl From for VRaw { fn from(html: AttrValue) -> Self { Self { html } diff --git a/packages/yew/src/virtual_dom/vsuspense.rs b/packages/yew/src/virtual_dom/vsuspense.rs index 1ae97b8603a..afd1b7f0dec 100644 --- a/packages/yew/src/virtual_dom/vsuspense.rs +++ b/packages/yew/src/virtual_dom/vsuspense.rs @@ -1,4 +1,5 @@ use super::{Key, VNode}; +use crate::html::ImplicitClone; /// This struct represents a suspendable DOM fragment. #[derive(Clone, Debug, PartialEq)] @@ -13,6 +14,8 @@ pub struct VSuspense { pub(crate) key: Option, } +impl ImplicitClone for VSuspense {} + impl VSuspense { pub fn new(children: VNode, fallback: VNode, suspended: bool, key: Option) -> Self { Self { diff --git a/packages/yew/src/virtual_dom/vtag.rs b/packages/yew/src/virtual_dom/vtag.rs index 266c1e8f339..60f70c53c14 100644 --- a/packages/yew/src/virtual_dom/vtag.rs +++ b/packages/yew/src/virtual_dom/vtag.rs @@ -1,6 +1,5 @@ //! This module contains the implementation of a virtual element node [VTag]. -use std::borrow::Cow; use std::cmp::PartialEq; use std::marker::PhantomData; use std::mem; @@ -10,7 +9,7 @@ use std::rc::Rc; use web_sys::{HtmlInputElement as InputElement, HtmlTextAreaElement as TextAreaElement}; use super::{ApplyAttributeAs, AttrValue, Attributes, Key, Listener, Listeners, VNode}; -use crate::html::{IntoPropValue, NodeRef}; +use crate::html::{ImplicitClone, IntoPropValue, NodeRef}; /// SVG namespace string used for creating svg elements pub const SVG_NAMESPACE: &str = "http://www.w3.org/2000/svg"; @@ -22,9 +21,17 @@ pub const MATHML_NAMESPACE: &str = "http://www.w3.org/1998/Math/MathML"; pub const HTML_NAMESPACE: &str = "http://www.w3.org/1999/xhtml"; /// Value field corresponding to an [Element]'s `value` property -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Debug, Eq, PartialEq)] pub(crate) struct Value(Option, PhantomData); +impl Clone for Value { + fn clone(&self) -> Self { + Self::new(self.0.clone()) + } +} + +impl ImplicitClone for Value {} + impl Default for Value { fn default() -> Self { Self::new(None) @@ -68,6 +75,8 @@ pub(crate) struct InputFields { pub(crate) checked: Option, } +impl ImplicitClone for InputFields {} + impl Deref for InputFields { type Target = Value; @@ -111,12 +120,14 @@ pub(crate) enum VTagInner { /// Fields for all other kinds of [VTag]s Other { /// A tag of the element. - tag: Cow<'static, str>, + tag: AttrValue, /// children of the element. children: VNode, }, } +impl ImplicitClone for VTagInner {} + /// A type for a virtual /// [Element](https://developer.mozilla.org/en-US/docs/Web/API/Element) /// representation. @@ -133,10 +144,12 @@ pub struct VTag { pub key: Option, } +impl ImplicitClone for VTag {} + impl VTag { /// Creates a new [VTag] instance with `tag` name (cannot be changed later in DOM). - pub fn new(tag: impl Into>) -> Self { - let tag: Cow<'static, str> = tag.into(); + pub fn new(tag: impl Into) -> Self { + let tag = tag.into(); Self::new_base( match &*tag.to_ascii_lowercase() { "input" => VTagInner::Input(Default::default()), @@ -226,7 +239,7 @@ impl VTag { #[doc(hidden)] #[allow(clippy::too_many_arguments)] pub fn __new_other( - tag: Cow<'static, str>, + tag: AttrValue, node_ref: NodeRef, key: Option, // at bottom for more readable macro-expanded coded diff --git a/packages/yew/src/virtual_dom/vtext.rs b/packages/yew/src/virtual_dom/vtext.rs index beb89acdad7..c1a3d5f38c0 100644 --- a/packages/yew/src/virtual_dom/vtext.rs +++ b/packages/yew/src/virtual_dom/vtext.rs @@ -3,6 +3,7 @@ use std::cmp::PartialEq; use super::AttrValue; +use crate::html::ImplicitClone; /// A type for a virtual /// [`TextNode`](https://developer.mozilla.org/en-US/docs/Web/API/Document/createTextNode) @@ -13,6 +14,8 @@ pub struct VText { pub text: AttrValue, } +impl ImplicitClone for VText {} + impl VText { /// Creates new virtual text node with a content. pub fn new(text: impl Into) -> Self { From df2d8ef5a31de667fb5c8e325014545bc3ac4e2f Mon Sep 17 00:00:00 2001 From: Cecile Tonglet Date: Sat, 30 Sep 2023 12:28:20 +0200 Subject: [PATCH 02/28] Faster clone for list and portal --- .../yew-macro/src/html_tree/html_element.rs | 4 +--- packages/yew-macro/src/html_tree/html_list.rs | 4 ++-- packages/yew-macro/src/html_tree/mod.rs | 2 +- packages/yew/src/html/component/children.rs | 3 ++- packages/yew/src/html/conversion/to_html.rs | 12 ++++++------ packages/yew/src/html/mod.rs | 2 +- packages/yew/src/virtual_dom/vnode.rs | 19 ++++++++++--------- packages/yew/src/virtual_dom/vportal.rs | 8 +++++--- 8 files changed, 28 insertions(+), 26 deletions(-) diff --git a/packages/yew-macro/src/html_tree/html_element.rs b/packages/yew-macro/src/html_tree/html_element.rs index 93ce729f97c..531a2964c43 100644 --- a/packages/yew-macro/src/html_tree/html_element.rs +++ b/packages/yew-macro/src/html_tree/html_element.rs @@ -415,9 +415,7 @@ impl ToTokens for HtmlElement { // e.g. html!{<@{"div"}/>} will set `#expr` to `{"div"}` // (note the extra braces). Hence the need for the `allow`. // Anyways to remove the braces? - let mut #vtag_name = ::std::convert::Into::< - ::std::borrow::Cow::<'static, ::std::primitive::str> - >::into(#expr); + let mut #vtag_name = ::yew::virtual_dom::AttrValue::from(#expr); ::std::debug_assert!( #vtag_name.is_ascii(), "a dynamic tag returned a tag name containing non ASCII characters: `{}`", diff --git a/packages/yew-macro/src/html_tree/html_list.rs b/packages/yew-macro/src/html_tree/html_list.rs index e48f250bfde..301b533a92c 100644 --- a/packages/yew-macro/src/html_tree/html_list.rs +++ b/packages/yew-macro/src/html_tree/html_list.rs @@ -78,9 +78,9 @@ impl ToTokens for HtmlList { }; tokens.extend(quote_spanned! {spanned.span()=> - ::yew::virtual_dom::VNode::VList( + ::yew::virtual_dom::VNode::VList(::std::rc::Rc::new( ::yew::virtual_dom::VList::with_children(#children, #key) - ) + )) }); } } diff --git a/packages/yew-macro/src/html_tree/mod.rs b/packages/yew-macro/src/html_tree/mod.rs index 0361231b6d4..533d5b1ff1e 100644 --- a/packages/yew-macro/src/html_tree/mod.rs +++ b/packages/yew-macro/src/html_tree/mod.rs @@ -123,7 +123,7 @@ impl ToTokens for HtmlTree { lint::lint_all(self); match self { HtmlTree::Empty => tokens.extend(quote! { - ::yew::virtual_dom::VNode::VList(::yew::virtual_dom::VList::new()) + ::yew::virtual_dom::VNode::default() }), HtmlTree::Component(comp) => comp.to_tokens(tokens), HtmlTree::Element(tag) => tag.to_tokens(tokens), diff --git a/packages/yew/src/html/component/children.rs b/packages/yew/src/html/component/children.rs index 94f6dc0d2e8..2a6f7e9d5a8 100644 --- a/packages/yew/src/html/component/children.rs +++ b/packages/yew/src/html/component/children.rs @@ -1,6 +1,7 @@ //! Component children module use std::fmt; +use std::rc::Rc; use crate::html::Html; use crate::virtual_dom::{VChild, VComp, VList, VNode}; @@ -241,7 +242,7 @@ impl From> for Html { } } - Html::VList(val.into()) + Html::VList(Rc::new(val.into())) } } diff --git a/packages/yew/src/html/conversion/to_html.rs b/packages/yew/src/html/conversion/to_html.rs index 2fba2d17b95..af15d5a179e 100644 --- a/packages/yew/src/html/conversion/to_html.rs +++ b/packages/yew/src/html/conversion/to_html.rs @@ -46,18 +46,18 @@ where { #[inline(always)] fn to_html(&self) -> Html { - Html::VList(VList::with_children( + Html::VList(Rc::new(VList::with_children( self.iter().map(ToHtml::to_html).collect(), None, - )) + ))) } #[inline(always)] fn into_html(self) -> Html { - Html::VList(VList::with_children( + Html::VList(Rc::new(VList::with_children( self.into_iter().map(ToHtml::into_html).collect(), None, - )) + ))) } } @@ -81,7 +81,7 @@ impl ToHtml for Vec { #[inline(always)] fn into_html(self) -> Html { - Html::VList(VList::with_children(self, None)) + Html::VList(Rc::new(VList::with_children(self, None))) } } @@ -105,7 +105,7 @@ impl ToHtml for VList { #[inline(always)] fn into_html(self) -> Html { - Html::VList(self) + Html::VList(Rc::new(self)) } } diff --git a/packages/yew/src/html/mod.rs b/packages/yew/src/html/mod.rs index 87e3cc03372..cbb0b1c5488 100644 --- a/packages/yew/src/html/mod.rs +++ b/packages/yew/src/html/mod.rs @@ -142,5 +142,5 @@ mod feat_csr { /// ## Relevant examples /// - [Portals](https://github.com/yewstack/yew/tree/master/examples/portals) pub fn create_portal(child: Html, host: Element) -> Html { - VNode::VPortal(VPortal::new(child, host)) + VNode::VPortal(Rc::new(VPortal::new(child, host))) } diff --git a/packages/yew/src/virtual_dom/vnode.rs b/packages/yew/src/virtual_dom/vnode.rs index 00fd8d25088..8ed18f29c9f 100644 --- a/packages/yew/src/virtual_dom/vnode.rs +++ b/packages/yew/src/virtual_dom/vnode.rs @@ -23,9 +23,9 @@ pub enum VNode { /// A bind between `VComp` and `Element`. VComp(Rc), /// A holder for a list of other nodes. - VList(VList), + VList(Rc), /// A portal to another part of the document - VPortal(VPortal), + VPortal(Rc), /// A holder for any `Node` (necessary for replacing node). VRef(Node), /// A suspendible document fragment. @@ -63,9 +63,10 @@ impl VNode { pub fn to_vlist_mut(&mut self) -> &mut VList { loop { match *self { - Self::VList(ref mut m) => return m, + Self::VList(ref mut m) => return Rc::make_mut(m), _ => { - *self = VNode::VList(VList::with_children(vec![mem::take(self)], None)); + *self = + VNode::VList(Rc::new(VList::with_children(vec![mem::take(self)], None))); } } } @@ -108,7 +109,7 @@ impl VNode { impl Default for VNode { fn default() -> Self { - VNode::VList(VList::default()) + VNode::VList(Rc::new(VList::default())) } } @@ -122,7 +123,7 @@ impl From for VNode { impl From for VNode { #[inline] fn from(vlist: VList) -> Self { - VNode::VList(vlist) + VNode::VList(Rc::new(vlist)) } } @@ -150,7 +151,7 @@ impl From for VNode { impl From for VNode { #[inline] fn from(vportal: VPortal) -> Self { - VNode::VPortal(vportal) + VNode::VPortal(Rc::new(vportal)) } } @@ -171,10 +172,10 @@ impl From for VNode { impl> FromIterator for VNode { fn from_iter>(iter: T) -> Self { - VNode::VList(VList::with_children( + VNode::VList(Rc::new(VList::with_children( iter.into_iter().map(|n| n.into()).collect(), None, - )) + ))) } } diff --git a/packages/yew/src/virtual_dom/vportal.rs b/packages/yew/src/virtual_dom/vportal.rs index d9472d9e696..1f46d5abe87 100644 --- a/packages/yew/src/virtual_dom/vportal.rs +++ b/packages/yew/src/virtual_dom/vportal.rs @@ -1,5 +1,7 @@ //! This module contains the implementation of a portal `VPortal`. +use std::rc::Rc; + use web_sys::{Element, Node}; use super::VNode; @@ -12,7 +14,7 @@ pub struct VPortal { /// The next sibling after the inserted content. Must be a child of `host`. pub inner_sibling: Option, /// The inserted node - pub node: Box, + pub node: Rc, } impl ImplicitClone for VPortal {} @@ -23,7 +25,7 @@ impl VPortal { Self { host, inner_sibling: None, - node: Box::new(content), + node: Rc::new(content), } } @@ -34,7 +36,7 @@ impl VPortal { Self { host, inner_sibling, - node: Box::new(content), + node: Rc::new(content), } } } From a7fd6607d893fbb86a096a0f6bb9a448d11087ef Mon Sep 17 00:00:00 2001 From: Cecile Tonglet Date: Sat, 30 Sep 2023 13:20:54 +0200 Subject: [PATCH 03/28] Fixes hopefully good --- packages/yew-macro/src/html_tree/html_list.rs | 4 +- packages/yew-macro/src/html_tree/mod.rs | 2 +- packages/yew/src/dom_bundle/blist.rs | 8 +-- packages/yew/src/dom_bundle/bnode.rs | 59 +++++++++++++++---- packages/yew/src/dom_bundle/btag/mod.rs | 5 +- packages/yew/src/html/classes.rs | 5 +- packages/yew/src/utils/mod.rs | 11 ++++ packages/yew/src/virtual_dom/vportal.rs | 11 +--- 8 files changed, 71 insertions(+), 34 deletions(-) diff --git a/packages/yew-macro/src/html_tree/html_list.rs b/packages/yew-macro/src/html_tree/html_list.rs index 301b533a92c..b10885ee413 100644 --- a/packages/yew-macro/src/html_tree/html_list.rs +++ b/packages/yew-macro/src/html_tree/html_list.rs @@ -78,9 +78,9 @@ impl ToTokens for HtmlList { }; tokens.extend(quote_spanned! {spanned.span()=> - ::yew::virtual_dom::VNode::VList(::std::rc::Rc::new( + ::yew::virtual_dom::VNode::from( ::yew::virtual_dom::VList::with_children(#children, #key) - )) + ) }); } } diff --git a/packages/yew-macro/src/html_tree/mod.rs b/packages/yew-macro/src/html_tree/mod.rs index 533d5b1ff1e..65b3f28ead4 100644 --- a/packages/yew-macro/src/html_tree/mod.rs +++ b/packages/yew-macro/src/html_tree/mod.rs @@ -375,7 +375,7 @@ impl ToTokens for HtmlRootBraced { tokens.extend(quote_spanned! {brace.span.span()=> { - ::yew::virtual_dom::VNode::VList( + ::yew::virtual_dom::VNode::from( ::yew::virtual_dom::VList::with_children(#children, ::std::option::Option::None) ) } diff --git a/packages/yew/src/dom_bundle/blist.rs b/packages/yew/src/dom_bundle/blist.rs index 93a9af585a8..ca7b95eb9d8 100644 --- a/packages/yew/src/dom_bundle/blist.rs +++ b/packages/yew/src/dom_bundle/blist.rs @@ -4,13 +4,13 @@ use std::cmp::Ordering; use std::collections::HashSet; use std::hash::Hash; use std::ops::Deref; -use std::rc::Rc; use web_sys::Element; use super::{test_log, BNode, BSubtree, DomSlot}; use crate::dom_bundle::{Reconcilable, ReconcileTarget}; use crate::html::AnyScope; +use crate::utils::RcExt; use crate::virtual_dom::{Key, VList, VNode, VText}; /// This struct represents a mounted [VList] @@ -30,10 +30,8 @@ impl VList { let children = self .children - .map(Rc::try_unwrap) - .unwrap_or_else(|| Ok(Vec::new())) - // Rc::unwrap_or_clone is not stable yet. - .unwrap_or_else(|m| m.to_vec()); + .map(|children| RcExt::unwrap_or_clone(children)) + .unwrap_or_default(); (self.key, fully_keyed, children) } diff --git a/packages/yew/src/dom_bundle/bnode.rs b/packages/yew/src/dom_bundle/bnode.rs index d6fdbe5aa47..46eb78108a1 100644 --- a/packages/yew/src/dom_bundle/bnode.rs +++ b/packages/yew/src/dom_bundle/bnode.rs @@ -7,6 +7,7 @@ use web_sys::{Element, Node}; use super::{BComp, BList, BPortal, BRaw, BSubtree, BSuspense, BTag, BText, DomSlot}; use crate::dom_bundle::{Reconcilable, ReconcileTarget}; use crate::html::AnyScope; +use crate::utils::RcExt; use crate::virtual_dom::{Key, VNode}; /// The bundle implementation to [VNode]. @@ -95,7 +96,8 @@ impl Reconcilable for VNode { ) -> (DomSlot, Self::Bundle) { match self { VNode::VTag(vtag) => { - let (node_ref, tag) = vtag.attach(root, parent_scope, parent, slot); + let (node_ref, tag) = + RcExt::unwrap_or_clone(vtag).attach(root, parent_scope, parent, slot); (node_ref, tag.into()) } VNode::VText(vtext) => { @@ -103,11 +105,13 @@ impl Reconcilable for VNode { (node_ref, text.into()) } VNode::VComp(vcomp) => { - let (node_ref, comp) = vcomp.attach(root, parent_scope, parent, slot); + let (node_ref, comp) = + RcExt::unwrap_or_clone(vcomp).attach(root, parent_scope, parent, slot); (node_ref, comp.into()) } VNode::VList(vlist) => { - let (node_ref, list) = vlist.attach(root, parent_scope, parent, slot); + let (node_ref, list) = + RcExt::unwrap_or_clone(vlist).attach(root, parent_scope, parent, slot); (node_ref, list.into()) } VNode::VRef(node) => { @@ -115,11 +119,13 @@ impl Reconcilable for VNode { (DomSlot::at(node.clone()), BNode::Ref(node)) } VNode::VPortal(vportal) => { - let (node_ref, portal) = vportal.attach(root, parent_scope, parent, slot); + let (node_ref, portal) = + RcExt::unwrap_or_clone(vportal).attach(root, parent_scope, parent, slot); (node_ref, portal.into()) } VNode::VSuspense(vsuspsense) => { - let (node_ref, suspsense) = vsuspsense.attach(root, parent_scope, parent, slot); + let (node_ref, suspsense) = + RcExt::unwrap_or_clone(vsuspsense).attach(root, parent_scope, parent, slot); (node_ref, suspsense.into()) } VNode::VRaw(vraw) => { @@ -149,19 +155,48 @@ impl Reconcilable for VNode { bundle: &mut BNode, ) -> DomSlot { match self { - VNode::VTag(vtag) => vtag.reconcile_node(root, parent_scope, parent, slot, bundle), + VNode::VTag(vtag) => RcExt::unwrap_or_clone(vtag).reconcile_node( + root, + parent_scope, + parent, + slot, + bundle, + ), VNode::VText(vtext) => vtext.reconcile_node(root, parent_scope, parent, slot, bundle), - VNode::VComp(vcomp) => vcomp.reconcile_node(root, parent_scope, parent, slot, bundle), - VNode::VList(vlist) => vlist.reconcile_node(root, parent_scope, parent, slot, bundle), + VNode::VComp(vcomp) => RcExt::unwrap_or_clone(vcomp).reconcile_node( + root, + parent_scope, + parent, + slot, + bundle, + ), + VNode::VList(vlist) => RcExt::unwrap_or_clone(vlist).reconcile_node( + root, + parent_scope, + parent, + slot, + bundle, + ), VNode::VRef(node) => match bundle { BNode::Ref(ref n) if &node == n => DomSlot::at(node), _ => VNode::VRef(node).replace(root, parent_scope, parent, slot, bundle), }, - VNode::VPortal(vportal) => { - vportal.reconcile_node(root, parent_scope, parent, slot, bundle) - } + VNode::VPortal(vportal) => RcExt::unwrap_or_clone(vportal).reconcile_node( + root, + parent_scope, + parent, + slot, + bundle, + ), VNode::VSuspense(vsuspsense) => { - vsuspsense.reconcile_node(root, parent_scope, parent, slot, bundle) + // TODO: replace this by Rc::unwrap_or_clone() when it becomes stable + RcExt::unwrap_or_clone(vsuspsense).reconcile_node( + root, + parent_scope, + parent, + slot, + bundle, + ) } VNode::VRaw(vraw) => vraw.reconcile_node(root, parent_scope, parent, slot, bundle), } diff --git a/packages/yew/src/dom_bundle/btag/mod.rs b/packages/yew/src/dom_bundle/btag/mod.rs index c590d6be6c5..2f40c8ffd45 100644 --- a/packages/yew/src/dom_bundle/btag/mod.rs +++ b/packages/yew/src/dom_bundle/btag/mod.rs @@ -3,7 +3,6 @@ mod attributes; mod listeners; -use std::borrow::Cow; use std::cell::RefCell; use std::collections::HashMap; use std::hint::unreachable_unchecked; @@ -18,7 +17,7 @@ use web_sys::{Element, HtmlTextAreaElement as TextAreaElement}; use super::{BNode, BSubtree, DomSlot, Reconcilable, ReconcileTarget}; use crate::html::AnyScope; use crate::virtual_dom::vtag::{InputFields, VTagInner, Value, MATHML_NAMESPACE, SVG_NAMESPACE}; -use crate::virtual_dom::{Attributes, Key, VTag}; +use crate::virtual_dom::{AttrValue, Attributes, Key, VTag}; use crate::NodeRef; /// Applies contained changes to DOM [web_sys::Element] @@ -51,7 +50,7 @@ enum BTagInner { /// Fields for all other kinds of [VTag]s Other { /// A tag of the element. - tag: Cow<'static, str>, + tag: AttrValue, /// Child node. child_bundle: BNode, }, diff --git a/packages/yew/src/html/classes.rs b/packages/yew/src/html/classes.rs index 0a5bb9cc9b0..37ca0c4b821 100644 --- a/packages/yew/src/html/classes.rs +++ b/packages/yew/src/html/classes.rs @@ -6,6 +6,7 @@ use implicit_clone::ImplicitClone; use indexmap::IndexSet; use super::IntoPropValue; +use crate::utils::RcExt; use crate::virtual_dom::AttrValue; /// A set of classes, cheap to clone. @@ -151,9 +152,7 @@ impl IntoIterator for Classes { #[inline] fn into_iter(self) -> Self::IntoIter { // NOTE: replace this by Rc::unwrap_or_clone() when it becomes stable - Rc::try_unwrap(self.set) - .unwrap_or_else(|rc| (*rc).clone()) - .into_iter() + RcExt::unwrap_or_clone(self.set).into_iter() } } diff --git a/packages/yew/src/utils/mod.rs b/packages/yew/src/utils/mod.rs index 98934ed054b..4f33ea672b2 100644 --- a/packages/yew/src/utils/mod.rs +++ b/packages/yew/src/utils/mod.rs @@ -64,3 +64,14 @@ pub fn print_node(n: &web_sys::Node) -> String { None => n.text_content().unwrap_or_default(), } } + +// NOTE: replace this by Rc::unwrap_or_clone() when it becomes stable +pub(crate) trait RcExt { + fn unwrap_or_clone(this: Self) -> T; +} + +impl RcExt for std::rc::Rc { + fn unwrap_or_clone(this: Self) -> T { + std::rc::Rc::try_unwrap(this).unwrap_or_else(|rc| (*rc).clone()) + } +} diff --git a/packages/yew/src/virtual_dom/vportal.rs b/packages/yew/src/virtual_dom/vportal.rs index 1f46d5abe87..ce39e82b9dd 100644 --- a/packages/yew/src/virtual_dom/vportal.rs +++ b/packages/yew/src/virtual_dom/vportal.rs @@ -1,11 +1,8 @@ //! This module contains the implementation of a portal `VPortal`. -use std::rc::Rc; - use web_sys::{Element, Node}; use super::VNode; -use crate::html::ImplicitClone; #[derive(Debug, Clone, PartialEq)] pub struct VPortal { @@ -14,18 +11,16 @@ pub struct VPortal { /// The next sibling after the inserted content. Must be a child of `host`. pub inner_sibling: Option, /// The inserted node - pub node: Rc, + pub node: VNode, } -impl ImplicitClone for VPortal {} - impl VPortal { /// Creates a [VPortal] rendering `content` in the DOM hierarchy under `host`. pub fn new(content: VNode, host: Element) -> Self { Self { host, inner_sibling: None, - node: Rc::new(content), + node: content, } } @@ -36,7 +31,7 @@ impl VPortal { Self { host, inner_sibling, - node: Rc::new(content), + node: content, } } } From ea8b6a7152a5d973bbaebc35e357c9a875b39890 Mon Sep 17 00:00:00 2001 From: Cecile Tonglet Date: Sat, 30 Sep 2023 13:27:13 +0200 Subject: [PATCH 04/28] clippy --- packages/yew/src/dom_bundle/blist.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/yew/src/dom_bundle/blist.rs b/packages/yew/src/dom_bundle/blist.rs index ca7b95eb9d8..ddd909027ea 100644 --- a/packages/yew/src/dom_bundle/blist.rs +++ b/packages/yew/src/dom_bundle/blist.rs @@ -30,7 +30,7 @@ impl VList { let children = self .children - .map(|children| RcExt::unwrap_or_clone(children)) + .map(RcExt::unwrap_or_clone) .unwrap_or_default(); (self.key, fully_keyed, children) From 56eb9c85274c1bc9010c9ee4b8c3b72947f1b62e Mon Sep 17 00:00:00 2001 From: Cecile Tonglet Date: Sat, 30 Sep 2023 13:30:36 +0200 Subject: [PATCH 05/28] more fixes hopefully good --- packages/yew/src/dom_bundle/bnode.rs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/packages/yew/src/dom_bundle/bnode.rs b/packages/yew/src/dom_bundle/bnode.rs index 46eb78108a1..b79821ff10d 100644 --- a/packages/yew/src/dom_bundle/bnode.rs +++ b/packages/yew/src/dom_bundle/bnode.rs @@ -281,10 +281,16 @@ mod feat_hydration { fragment: &mut Fragment, ) -> Self::Bundle { match self { - VNode::VTag(vtag) => vtag.hydrate(root, parent_scope, parent, fragment).into(), + VNode::VTag(vtag) => RcExt::unwrap_or_clone(vtag) + .hydrate(root, parent_scope, parent, fragment) + .into(), VNode::VText(vtext) => vtext.hydrate(root, parent_scope, parent, fragment).into(), - VNode::VComp(vcomp) => vcomp.hydrate(root, parent_scope, parent, fragment).into(), - VNode::VList(vlist) => vlist.hydrate(root, parent_scope, parent, fragment).into(), + VNode::VComp(vcomp) => RcExt::unwrap_or_clone(vcomp) + .hydrate(root, parent_scope, parent, fragment) + .into(), + VNode::VList(vlist) => RcExt::unwrap_or_clone(vlist) + .hydrate(root, parent_scope, parent, fragment) + .into(), // You cannot hydrate a VRef. VNode::VRef(_) => { panic!( @@ -299,7 +305,7 @@ mod feat_hydration { use_effect." ) } - VNode::VSuspense(vsuspense) => vsuspense + VNode::VSuspense(vsuspense) => RcExt::unwrap_or_clone(vsuspense) .hydrate(root, parent_scope, parent, fragment) .into(), VNode::VRaw(vraw) => vraw.hydrate(root, parent_scope, parent, fragment).into(), From a0151778156425182c0fb695dc980355863aee39 Mon Sep 17 00:00:00 2001 From: Cecile Tonglet Date: Sat, 30 Sep 2023 13:32:54 +0200 Subject: [PATCH 06/28] rustfmt --- packages/yew/src/virtual_dom/listeners.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/yew/src/virtual_dom/listeners.rs b/packages/yew/src/virtual_dom/listeners.rs index 7008e79b00f..f96dead2f39 100644 --- a/packages/yew/src/virtual_dom/listeners.rs +++ b/packages/yew/src/virtual_dom/listeners.rs @@ -1,6 +1,7 @@ -use crate::html::ImplicitClone; use std::rc::Rc; +use crate::html::ImplicitClone; + /// The [Listener] trait is an universal implementation of an event listener /// which is used to bind Rust-listener to JS-listener (DOM). pub trait Listener { From 9f296630e6cbe10b04d63f471248fde5418aa945 Mon Sep 17 00:00:00 2001 From: Cecile Tonglet Date: Sat, 30 Sep 2023 13:39:20 +0200 Subject: [PATCH 07/28] More fixes --- packages/yew/src/dom_bundle/bportal.rs | 18 ++++++++++-------- packages/yew/src/dom_bundle/btag/mod.rs | 9 ++++++--- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/packages/yew/src/dom_bundle/bportal.rs b/packages/yew/src/dom_bundle/bportal.rs index a7e5d76c9a0..9792383101b 100644 --- a/packages/yew/src/dom_bundle/bportal.rs +++ b/packages/yew/src/dom_bundle/bportal.rs @@ -123,6 +123,8 @@ impl BPortal { mod layout_tests { extern crate self as yew; + use std::rc::Rc; + use gloo::utils::document; use wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure}; use web_sys::HtmlInputElement; @@ -151,10 +153,10 @@ mod layout_tests {
{VNode::VRef(first_target.clone().into())} {VNode::VRef(second_target.clone().into())} - {VNode::VPortal(VPortal::new( + {VNode::VPortal(Rc::new(VPortal::new( html! { {"PORTAL"} }, first_target.clone(), - ))} + )))} {"AFTER"}
}, @@ -166,10 +168,10 @@ mod layout_tests {
{VNode::VRef(first_target.clone().into())} {VNode::VRef(second_target.clone().into())} - {VNode::VPortal(VPortal::new( + {VNode::VPortal(Rc::new(VPortal::new( html! { {"PORTAL"} }, second_target.clone(), - ))} + )))} {"AFTER"}
}, @@ -181,10 +183,10 @@ mod layout_tests {
{VNode::VRef(first_target.clone().into())} {VNode::VRef(second_target.clone().into())} - {VNode::VPortal(VPortal::new( + {VNode::VPortal(Rc::new(VPortal::new( html! { <> {"PORTAL"} }, second_target.clone(), - ))} + )))} {"AFTER"}
}, @@ -207,11 +209,11 @@ mod layout_tests { node: html! {
{VNode::VRef(target_with_child.clone().into())} - {VNode::VPortal(VPortal::new_before( + {VNode::VPortal(Rc::new(VPortal::new_before( html! { {"PORTAL"} }, target_with_child.clone(), Some(target_child.clone().into()), - ))} + )))}
}, expected: "
PORTAL
", diff --git a/packages/yew/src/dom_bundle/btag/mod.rs b/packages/yew/src/dom_bundle/btag/mod.rs index 2f40c8ffd45..8a97c1ef33d 100644 --- a/packages/yew/src/dom_bundle/btag/mod.rs +++ b/packages/yew/src/dom_bundle/btag/mod.rs @@ -406,6 +406,8 @@ mod feat_hydration { #[cfg(target_arch = "wasm32")] #[cfg(test)] mod tests { + use std::rc::Rc; + use wasm_bindgen::JsCast; use wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure}; use web_sys::HtmlInputElement as InputElement; @@ -413,6 +415,7 @@ mod tests { use super::*; use crate::dom_bundle::utils::setup_parent; use crate::dom_bundle::{BNode, Reconcilable, ReconcileTarget}; + use crate::utils::RcExt; use crate::virtual_dom::vtag::{HTML_NAMESPACE, SVG_NAMESPACE}; use crate::virtual_dom::{AttrValue, VNode, VTag}; use crate::{html, Html, NodeRef}; @@ -563,7 +566,7 @@ mod tests { fn assert_vtag(node: VNode) -> VTag { if let VNode::VTag(vtag) = node { - return *vtag; + return RcExt::unwrap_or_clone(vtag); } panic!("should be vtag"); } @@ -970,7 +973,7 @@ mod tests { vtag.add_attribute("disabled", "disabled"); vtag.add_attribute("tabindex", "0"); - let elem = VNode::VTag(Box::new(vtag)); + let elem = VNode::VTag(Rc::new(vtag)); let (_, mut elem) = elem.attach(&root, &scope, &parent, DomSlot::at_end()); @@ -978,7 +981,7 @@ mod tests { let mut vtag = VTag::new("div"); vtag.node_ref = test_ref.clone(); vtag.add_attribute("tabindex", "0"); - let next_elem = VNode::VTag(Box::new(vtag)); + let next_elem = VNode::VTag(Rc::new(vtag)); let elem_vtag = assert_vtag(next_elem); // Sync happens here From bcd68c062d2e421e926bafd1365efcf5e2f6216f Mon Sep 17 00:00:00 2001 From: Cecile Tonglet Date: Sat, 30 Sep 2023 13:44:29 +0200 Subject: [PATCH 08/28] more fixes... --- examples/futures/src/markdown.rs | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/examples/futures/src/markdown.rs b/examples/futures/src/markdown.rs index 5c85b7a55e4..afdad6bf98f 100644 --- a/examples/futures/src/markdown.rs +++ b/examples/futures/src/markdown.rs @@ -1,5 +1,7 @@ /// Original author of this code is [Nathan Ringo](https://github.com/remexre) /// Source: https://github.com/acmumn/mentoring/blob/master/web-client/src/view/markdown.rs +use std::rc::Rc; + use pulldown_cmark::{Alignment, CodeBlockKind, Event, Options, Parser, Tag}; use yew::virtual_dom::{VNode, VTag, VText}; use yew::{html, Classes, Html}; @@ -56,16 +58,22 @@ pub fn render_markdown(src: &str) -> Html { if let Some(top_children) = top.children_mut() { for r in top_children.to_vlist_mut().iter_mut() { if let VNode::VTag(ref mut vtag) = r { - if let Some(vtag_children) = vtag.children_mut() { + if let Some(vtag_children) = Rc::make_mut(vtag).children_mut() { for (i, c) in vtag_children.to_vlist_mut().iter_mut().enumerate() { if let VNode::VTag(ref mut vtag) = c { match aligns[i] { Alignment::None => {} - Alignment::Left => add_class(vtag, "text-left"), - Alignment::Center => add_class(vtag, "text-center"), - Alignment::Right => add_class(vtag, "text-right"), + Alignment::Left => { + add_class(Rc::make_mut(vtag), "text-left") + } + Alignment::Center => { + add_class(Rc::make_mut(vtag), "text-center") + } + Alignment::Right => { + add_class(Rc::make_mut(vtag), "text-right") + } } } } @@ -79,7 +87,7 @@ pub fn render_markdown(src: &str) -> Html { if let VNode::VTag(ref mut vtag) = c { // TODO // vtag.tag = "th".into(); - vtag.add_attribute("scope", "col"); + Rc::make_mut(vtag).add_attribute("scope", "col"); } } } @@ -99,7 +107,7 @@ pub fn render_markdown(src: &str) -> Html { } if elems.len() == 1 { - VNode::VTag(Box::new(elems.pop().unwrap())) + VNode::VTag(Rc::new(elems.pop().unwrap())) } else { html! {
{ for elems.into_iter() }
From afdf83c42f1f81fd0566654bc5e43640fc0a818c Mon Sep 17 00:00:00 2001 From: Cecile Tonglet Date: Sat, 30 Sep 2023 14:01:44 +0200 Subject: [PATCH 09/28] more fixes --- packages/yew-macro/src/html_tree/html_element.rs | 2 +- packages/yew-macro/src/html_tree/html_list.rs | 4 ++-- packages/yew-macro/src/html_tree/mod.rs | 2 +- packages/yew/src/virtual_dom/vtag.rs | 7 +++++-- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/packages/yew-macro/src/html_tree/html_element.rs b/packages/yew-macro/src/html_tree/html_element.rs index 531a2964c43..b67c1f53f8c 100644 --- a/packages/yew-macro/src/html_tree/html_element.rs +++ b/packages/yew-macro/src/html_tree/html_element.rs @@ -359,7 +359,7 @@ impl ToTokens for HtmlElement { quote! { ::std::convert::Into::<::yew::virtual_dom::VNode>::into( ::yew::virtual_dom::VTag::__new_other( - ::yew::virtual_dom::AttrValue::from(#name), + #name, #node_ref, #key, #attributes, diff --git a/packages/yew-macro/src/html_tree/html_list.rs b/packages/yew-macro/src/html_tree/html_list.rs index b10885ee413..301b533a92c 100644 --- a/packages/yew-macro/src/html_tree/html_list.rs +++ b/packages/yew-macro/src/html_tree/html_list.rs @@ -78,9 +78,9 @@ impl ToTokens for HtmlList { }; tokens.extend(quote_spanned! {spanned.span()=> - ::yew::virtual_dom::VNode::from( + ::yew::virtual_dom::VNode::VList(::std::rc::Rc::new( ::yew::virtual_dom::VList::with_children(#children, #key) - ) + )) }); } } diff --git a/packages/yew-macro/src/html_tree/mod.rs b/packages/yew-macro/src/html_tree/mod.rs index 65b3f28ead4..2474c97b820 100644 --- a/packages/yew-macro/src/html_tree/mod.rs +++ b/packages/yew-macro/src/html_tree/mod.rs @@ -123,7 +123,7 @@ impl ToTokens for HtmlTree { lint::lint_all(self); match self { HtmlTree::Empty => tokens.extend(quote! { - ::yew::virtual_dom::VNode::default() + <::yew::virtual_dom::VNode as ::std::default::Default>::default() }), HtmlTree::Component(comp) => comp.to_tokens(tokens), HtmlTree::Element(tag) => tag.to_tokens(tokens), diff --git a/packages/yew/src/virtual_dom/vtag.rs b/packages/yew/src/virtual_dom/vtag.rs index 60f70c53c14..632b297f298 100644 --- a/packages/yew/src/virtual_dom/vtag.rs +++ b/packages/yew/src/virtual_dom/vtag.rs @@ -239,7 +239,7 @@ impl VTag { #[doc(hidden)] #[allow(clippy::too_many_arguments)] pub fn __new_other( - tag: AttrValue, + tag: impl Into, node_ref: NodeRef, key: Option, // at bottom for more readable macro-expanded coded @@ -248,7 +248,10 @@ impl VTag { children: VNode, ) -> Self { VTag::new_base( - VTagInner::Other { tag, children }, + VTagInner::Other { + tag: tag.into(), + children, + }, node_ref, key, attributes, From 7717bb06d12a8cd1580a586dc09382d2cd20e49e Mon Sep 17 00:00:00 2001 From: Cecile Tonglet Date: Sat, 30 Sep 2023 14:03:39 +0200 Subject: [PATCH 10/28] Update element-fail.stderr --- .../tests/html_macro/element-fail.stderr | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/packages/yew-macro/tests/html_macro/element-fail.stderr b/packages/yew-macro/tests/html_macro/element-fail.stderr index d05a7cfad41..96f07cac42d 100644 --- a/packages/yew-macro/tests/html_macro/element-fail.stderr +++ b/packages/yew-macro/tests/html_macro/element-fail.stderr @@ -703,20 +703,14 @@ error[E0277]: the trait bound `(): IntoPropValue` is not satisfied and $N others = note: this error originates in the macro `html` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0277]: the trait bound `Cow<'static, str>: From<{integer}>` is not satisfied +error[E0277]: the trait bound `implicit_clone::unsync::IString: From<{integer}>` is not satisfied --> tests/html_macro/element-fail.rs:77:15 | 77 | html! { <@{55}> }; - | ^^^^ the trait `From<{integer}>` is not implemented for `Cow<'static, str>` + | ^^^^ the trait `From<{integer}>` is not implemented for `implicit_clone::unsync::IString` | = help: the following other types implement trait `From`: - as From<&'a CStr>> - as From<&'a CString>> - as From> - as From<&'a OsStr>> - as From<&'a OsString>> - as From> - as From<&'a Path>> - as From<&'a PathBuf>> - and $N others - = note: required because of the requirements on the impl of `Into>` for `{integer}` + > + >> + >> + > From 5282d96f7d4ee83fff5a748e0b343e4fb4394c96 Mon Sep 17 00:00:00 2001 From: Cecile Tonglet Date: Sat, 30 Sep 2023 14:42:19 +0200 Subject: [PATCH 11/28] Macro fixes... --- packages/yew-macro/src/html_tree/html_element.rs | 6 ++++-- packages/yew-macro/src/html_tree/mod.rs | 4 ++-- .../tests/html_macro/component-any-children-pass.rs | 8 ++++---- packages/yew-macro/tests/html_macro/component-pass.rs | 8 ++++---- packages/yew-macro/tests/html_macro/element-fail.stderr | 1 + packages/yew/src/virtual_dom/vtag.rs | 7 ++----- 6 files changed, 17 insertions(+), 17 deletions(-) diff --git a/packages/yew-macro/src/html_tree/html_element.rs b/packages/yew-macro/src/html_tree/html_element.rs index b67c1f53f8c..a501644941b 100644 --- a/packages/yew-macro/src/html_tree/html_element.rs +++ b/packages/yew-macro/src/html_tree/html_element.rs @@ -359,7 +359,7 @@ impl ToTokens for HtmlElement { quote! { ::std::convert::Into::<::yew::virtual_dom::VNode>::into( ::yew::virtual_dom::VTag::__new_other( - #name, + ::yew::virtual_dom::AttrValue::Static(#name), #node_ref, #key, #attributes, @@ -415,7 +415,9 @@ impl ToTokens for HtmlElement { // e.g. html!{<@{"div"}/>} will set `#expr` to `{"div"}` // (note the extra braces). Hence the need for the `allow`. // Anyways to remove the braces? - let mut #vtag_name = ::yew::virtual_dom::AttrValue::from(#expr); + let mut #vtag_name = ::std::convert::Into::< + ::yew::virtual_dom::AttrValue + >::into(#expr); ::std::debug_assert!( #vtag_name.is_ascii(), "a dynamic tag returned a tag name containing non ASCII characters: `{}`", diff --git a/packages/yew-macro/src/html_tree/mod.rs b/packages/yew-macro/src/html_tree/mod.rs index 2474c97b820..266ea31bfd8 100644 --- a/packages/yew-macro/src/html_tree/mod.rs +++ b/packages/yew-macro/src/html_tree/mod.rs @@ -375,9 +375,9 @@ impl ToTokens for HtmlRootBraced { tokens.extend(quote_spanned! {brace.span.span()=> { - ::yew::virtual_dom::VNode::from( + ::yew::virtual_dom::VNode::VList(::std::rc::Rc::new( ::yew::virtual_dom::VList::with_children(#children, ::std::option::Option::None) - ) + )) } }); } diff --git a/packages/yew-macro/tests/html_macro/component-any-children-pass.rs b/packages/yew-macro/tests/html_macro/component-any-children-pass.rs index cf5a924e506..c9b9e0f1777 100644 --- a/packages/yew-macro/tests/html_macro/component-any-children-pass.rs +++ b/packages/yew-macro/tests/html_macro/component-any-children-pass.rs @@ -83,12 +83,12 @@ impl ::std::convert::From<::yew::virtual_dom::VChild> for ChildrenVari impl ::std::convert::Into<::yew::virtual_dom::VNode> for ChildrenVariants { fn into(self) -> ::yew::virtual_dom::VNode { match self { - Self::Child(comp) => ::yew::virtual_dom::VNode::VComp(::std::convert::Into::< + Self::Child(comp) => ::yew::virtual_dom::VNode::VComp(::std::rc::Rc::new(::std::convert::Into::< ::yew::virtual_dom::VComp, - >::into(comp)), - Self::AltChild(comp) => ::yew::virtual_dom::VNode::VComp(::std::convert::Into::< + >::into(comp))), + Self::AltChild(comp) => ::yew::virtual_dom::VNode::VComp(::std::rc::Rc::new(::std::convert::Into::< ::yew::virtual_dom::VComp, - >::into(comp)), + >::into(comp))), } } } diff --git a/packages/yew-macro/tests/html_macro/component-pass.rs b/packages/yew-macro/tests/html_macro/component-pass.rs index 61f0de060f8..f971f66c4cb 100644 --- a/packages/yew-macro/tests/html_macro/component-pass.rs +++ b/packages/yew-macro/tests/html_macro/component-pass.rs @@ -82,12 +82,12 @@ impl ::std::convert::From<::yew::virtual_dom::VChild> for ChildrenVari impl ::std::convert::Into<::yew::virtual_dom::VNode> for ChildrenVariants { fn into(self) -> ::yew::virtual_dom::VNode { match self { - Self::Child(comp) => ::yew::virtual_dom::VNode::VComp(::std::convert::Into::< + Self::Child(comp) => ::yew::virtual_dom::VNode::VComp(::std::rc::Rc::new(::std::convert::Into::< ::yew::virtual_dom::VComp, - >::into(comp)), - Self::AltChild(comp) => ::yew::virtual_dom::VNode::VComp(::std::convert::Into::< + >::into(comp))), + Self::AltChild(comp) => ::yew::virtual_dom::VNode::VComp(::std::rc::Rc::new(::std::convert::Into::< ::yew::virtual_dom::VComp, - >::into(comp)), + >::into(comp))), } } } diff --git a/packages/yew-macro/tests/html_macro/element-fail.stderr b/packages/yew-macro/tests/html_macro/element-fail.stderr index 96f07cac42d..842553fab43 100644 --- a/packages/yew-macro/tests/html_macro/element-fail.stderr +++ b/packages/yew-macro/tests/html_macro/element-fail.stderr @@ -714,3 +714,4 @@ error[E0277]: the trait bound `implicit_clone::unsync::IString: From<{integer}>` >> >> > + = note: required because of the requirements on the impl of `Into` for `{integer}` diff --git a/packages/yew/src/virtual_dom/vtag.rs b/packages/yew/src/virtual_dom/vtag.rs index 632b297f298..60f70c53c14 100644 --- a/packages/yew/src/virtual_dom/vtag.rs +++ b/packages/yew/src/virtual_dom/vtag.rs @@ -239,7 +239,7 @@ impl VTag { #[doc(hidden)] #[allow(clippy::too_many_arguments)] pub fn __new_other( - tag: impl Into, + tag: AttrValue, node_ref: NodeRef, key: Option, // at bottom for more readable macro-expanded coded @@ -248,10 +248,7 @@ impl VTag { children: VNode, ) -> Self { VTag::new_base( - VTagInner::Other { - tag: tag.into(), - children, - }, + VTagInner::Other { tag, children }, node_ref, key, attributes, From 95d1438546dddaefc83124333b981f8134f8bc03 Mon Sep 17 00:00:00 2001 From: Cecile Tonglet Date: Sat, 30 Sep 2023 15:18:35 +0200 Subject: [PATCH 12/28] CLEANUP --- packages/yew/src/dom_bundle/bnode.rs | 17 +++++++---------- packages/yew/src/html/classes.rs | 1 - packages/yew/src/virtual_dom/vsuspense.rs | 8 ++++---- 3 files changed, 11 insertions(+), 15 deletions(-) diff --git a/packages/yew/src/dom_bundle/bnode.rs b/packages/yew/src/dom_bundle/bnode.rs index b79821ff10d..2f59acfe47f 100644 --- a/packages/yew/src/dom_bundle/bnode.rs +++ b/packages/yew/src/dom_bundle/bnode.rs @@ -188,16 +188,13 @@ impl Reconcilable for VNode { slot, bundle, ), - VNode::VSuspense(vsuspsense) => { - // TODO: replace this by Rc::unwrap_or_clone() when it becomes stable - RcExt::unwrap_or_clone(vsuspsense).reconcile_node( - root, - parent_scope, - parent, - slot, - bundle, - ) - } + VNode::VSuspense(vsuspsense) => RcExt::unwrap_or_clone(vsuspsense).reconcile_node( + root, + parent_scope, + parent, + slot, + bundle, + ), VNode::VRaw(vraw) => vraw.reconcile_node(root, parent_scope, parent, slot, bundle), } } diff --git a/packages/yew/src/html/classes.rs b/packages/yew/src/html/classes.rs index 37ca0c4b821..941ec617bf2 100644 --- a/packages/yew/src/html/classes.rs +++ b/packages/yew/src/html/classes.rs @@ -151,7 +151,6 @@ impl IntoIterator for Classes { #[inline] fn into_iter(self) -> Self::IntoIter { - // NOTE: replace this by Rc::unwrap_or_clone() when it becomes stable RcExt::unwrap_or_clone(self.set).into_iter() } } diff --git a/packages/yew/src/virtual_dom/vsuspense.rs b/packages/yew/src/virtual_dom/vsuspense.rs index afd1b7f0dec..8167f4fb2e1 100644 --- a/packages/yew/src/virtual_dom/vsuspense.rs +++ b/packages/yew/src/virtual_dom/vsuspense.rs @@ -5,9 +5,9 @@ use crate::html::ImplicitClone; #[derive(Clone, Debug, PartialEq)] pub struct VSuspense { /// Child nodes. - pub(crate) children: Box, + pub(crate) children: VNode, /// Fallback nodes when suspended. - pub(crate) fallback: Box, + pub(crate) fallback: VNode, /// Whether the current status is suspended. pub(crate) suspended: bool, /// The Key. @@ -19,8 +19,8 @@ impl ImplicitClone for VSuspense {} impl VSuspense { pub fn new(children: VNode, fallback: VNode, suspended: bool, key: Option) -> Self { Self { - children: children.into(), - fallback: fallback.into(), + children, + fallback, suspended, key, } From 39305baca88502e09d1139b908ce330d48c346f6 Mon Sep 17 00:00:00 2001 From: Cecile Tonglet Date: Wed, 18 Oct 2023 15:21:33 +0200 Subject: [PATCH 13/28] Benchmark with divan --- Cargo.lock | 112 +++++++++++++++++++++++++- tools/benchmark-core/Cargo.toml | 14 ++++ tools/benchmark-core/benches/vnode.rs | 27 +++++++ 3 files changed, 150 insertions(+), 3 deletions(-) create mode 100644 tools/benchmark-core/Cargo.toml create mode 100644 tools/benchmark-core/benches/vnode.rs diff --git a/Cargo.lock b/Cargo.lock index cc019a2dcaa..a6e8043c1fe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -239,6 +239,14 @@ dependencies = [ "serde", ] +[[package]] +name = "benchmark-core" +version = "0.1.0" +dependencies = [ + "divan", + "yew", +] + [[package]] name = "benchmark-ssr" version = "0.1.0" @@ -402,6 +410,7 @@ dependencies = [ "anstyle", "clap_lex", "strsim", + "terminal_size", ] [[package]] @@ -462,6 +471,12 @@ dependencies = [ "yew", ] +[[package]] +name = "condtype" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf0a07a401f374238ab8e2f11a104d2851bf9ce711ec69804834de8af45c7af" + [[package]] name = "console" version = "0.15.7" @@ -515,6 +530,17 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" +[[package]] +name = "core_affinity" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622892f5635ce1fc38c8f16dfc938553ed64af482edb5e150bf4caedbfcb2304" +dependencies = [ + "libc", + "num_cpus", + "winapi", +] + [[package]] name = "counter" version = "0.1.1" @@ -658,6 +684,31 @@ dependencies = [ "crypto-common", ] +[[package]] +name = "divan" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b83bf1f6d0621a46a00a7260700b15c608ae8b0aa65e830197ab216c24ca087" +dependencies = [ + "clap", + "condtype", + "core_affinity", + "divan-macros", + "linkme", + "regex-lite", +] + +[[package]] +name = "divan-macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6e12f661a0897d97d90d5f4d2c441ad947c560863b0e093b19dd8b309a1326c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.37", +] + [[package]] name = "dyn_create_destroy_apps" version = "0.1.0" @@ -1701,7 +1752,7 @@ checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" dependencies = [ "hermit-abi 0.3.1", "io-lifetimes", - "rustix", + "rustix 0.37.20", "windows-sys 0.48.0", ] @@ -1863,12 +1914,38 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "linkme" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ed2ee9464ff9707af8e9ad834cffa4802f072caad90639c583dd3c62e6e608" +dependencies = [ + "linkme-impl", +] + +[[package]] +name = "linkme-impl" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba125974b109d512fccbc6c0244e7580143e460895dfd6ea7f8bbb692fd94396" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.37", +] + [[package]] name = "linux-raw-sys" version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" +[[package]] +name = "linux-raw-sys" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f" + [[package]] name = "lipsum" version = "0.9.0" @@ -2408,6 +2485,12 @@ dependencies = [ "regex-syntax", ] +[[package]] +name = "regex-lite" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30b661b2f27137bdbc16f00eda72866a92bb28af1753ffbd56744fb6e2e9cd8e" + [[package]] name = "regex-syntax" version = "0.7.5" @@ -2499,7 +2582,20 @@ dependencies = [ "errno", "io-lifetimes", "libc", - "linux-raw-sys", + "linux-raw-sys 0.3.8", + "windows-sys 0.48.0", +] + +[[package]] +name = "rustix" +version = "0.38.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7db8590df6dfcd144d22afd1b83b36c21a18d7cbc1dc4bb5295a8712e9eb662" +dependencies = [ + "bitflags 2.4.0", + "errno", + "libc", + "linux-raw-sys 0.4.10", "windows-sys 0.48.0", ] @@ -2846,7 +2942,7 @@ dependencies = [ "cfg-if", "fastrand", "redox_syscall", - "rustix", + "rustix 0.37.20", "windows-sys 0.48.0", ] @@ -2859,6 +2955,16 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "terminal_size" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7" +dependencies = [ + "rustix 0.38.13", + "windows-sys 0.48.0", +] + [[package]] name = "thiserror" version = "1.0.49" diff --git a/tools/benchmark-core/Cargo.toml b/tools/benchmark-core/Cargo.toml new file mode 100644 index 00000000000..871323c0700 --- /dev/null +++ b/tools/benchmark-core/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "benchmark-core" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[[bench]] +name = "vnode" +harness = false + +[dependencies] +divan = "0.1.0" +yew = { path = "../../packages/yew" } diff --git a/tools/benchmark-core/benches/vnode.rs b/tools/benchmark-core/benches/vnode.rs new file mode 100644 index 00000000000..bfac7d38869 --- /dev/null +++ b/tools/benchmark-core/benches/vnode.rs @@ -0,0 +1,27 @@ +use yew::prelude::*; + +fn main() { + divan::main(); +} + +#[function_component] +fn Stuff(_: &()) -> Html { + html! { +

{"A custom component"}

+ } +} + +#[divan::bench] +fn vnode_clone(bencher: divan::Bencher) { + let html = html! { +
+ {"Hello"} + {"World"} + +
+ }; + + bencher.bench_local(move || { + let _ = divan::black_box(html.clone()); + }); +} From f893caf1bbd502a993f8228fdf05caf1f238d795 Mon Sep 17 00:00:00 2001 From: Cecile Tonglet Date: Wed, 18 Oct 2023 15:46:16 +0200 Subject: [PATCH 14/28] WIP workflow --- .github/workflows/benchmark-core.yml | 67 +++++++++++++++ .github/workflows/post-benchmark-core.yml | 100 ++++++++++++++++++++++ tools/benchmark-core/benches/vnode.rs | 2 +- 3 files changed, 168 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/benchmark-core.yml create mode 100644 .github/workflows/post-benchmark-core.yml diff --git a/.github/workflows/benchmark-core.yml b/.github/workflows/benchmark-core.yml new file mode 100644 index 00000000000..ef821f20ed5 --- /dev/null +++ b/.github/workflows/benchmark-core.yml @@ -0,0 +1,67 @@ +--- +name: Benchmark - SSR + +on: + pull_request: + branches: [master] + paths: + - .github/workflows/benchmark-core.yml + - "packages/yew/**" + - "tools/benchmark-core/**" + +jobs: + benchmark-core: + name: Benchmark - core + runs-on: ubuntu-latest + + steps: + - name: Checkout master + uses: actions/checkout@v3 + with: + repository: "yewstack/yew" + ref: master + path: yew-master + + - name: Checkout pull request + uses: actions/checkout@v3 + with: + path: current-pr + + - name: Setup toolchain + uses: dtolnay/rust-toolchain@master + with: + toolchain: stable + + - name: Restore Rust cache for master + uses: Swatinem/rust-cache@v2 + with: + working-directory: yew-master + key: master + + - name: Restore Rust cache for current pull request + uses: Swatinem/rust-cache@v2 + with: + working-directory: current-pr + key: pr + + - name: Run pull request benchmark + run: cargo bench -q > ../output.log + working-directory: current-pr/tools/benchmark-core + + - name: Run master benchmark + run: cargo bench -q > ../output.log + working-directory: yew-master/tools/benchmark-core + + - name: Write Pull Request ID + run: | + echo "${{ github.event.number }}" > .PR_NUMBER + + - name: Upload Artifact + uses: actions/upload-artifact@v3 + with: + name: benchmark-core + path: | + .PR_NUMBER + yew-master/tools/output.log + current-pr/tools/output.log + retention-days: 1 diff --git a/.github/workflows/post-benchmark-core.yml b/.github/workflows/post-benchmark-core.yml new file mode 100644 index 00000000000..ff011542164 --- /dev/null +++ b/.github/workflows/post-benchmark-core.yml @@ -0,0 +1,100 @@ +--- +name: Post Comment for Benchmark - core + +on: + workflow_run: + workflows: ["Benchmark - core"] + types: + - completed + +jobs: + post-benchmark-core: + if: github.event.workflow_run.event == 'pull_request' + name: Post Comment on Pull Request + runs-on: ubuntu-latest + + steps: + - name: Download Repository + uses: actions/checkout@v3 + + - name: Download Artifact + uses: Legit-Labs/action-download-artifact@v2 + with: + github_token: "${{ secrets.GITHUB_TOKEN }}" + workflow: benchmark-core.yml + run_id: ${{ github.event.workflow_run.id }} + name: benchmark-core + path: "benchmark-core/" + + - name: Make pull request comment + run: | + cat - >>comment.txt <>comment.txt + cat - >>comment.txt <> comment.txt + ``` + EOF + cat benchmark-core/current-pr/tools/output.json >>comment.txt + cat - >>comment.txt <> $GITHUB_ENV + + - name: Post Comment + uses: actions/github-script@v6 + with: + script: | + const fs = require('fs'); + + const commentInfo = { + ...context.repo, + issue_number: ${{ env.PR_NUMBER }}, + }; + + const comment = { + ...commentInfo, + body: fs.readFileSync("comment.txt", 'utf-8'), + }; + + function isCommentByBot(comment) { + return comment.user.type === "Bot" && comment.body.includes("### Benchmark - core"); + } + + let commentId = null; + const comments = (await github.rest.issues.listComments(commentInfo)).data; + for (let i = comments.length; i--; ) { + const c = comments[i]; + if (isCommentByBot(c)) { + commentId = c.id; + break; + } + } + + if (commentId) { + try { + await github.rest.issues.updateComment({ + ...context.repo, + comment_id: commentId, + body: comment.body, + }); + } catch (e) { + commentId = null; + } + } + + if (!commentId) { + await github.rest.issues.createComment(comment); + } diff --git a/tools/benchmark-core/benches/vnode.rs b/tools/benchmark-core/benches/vnode.rs index bfac7d38869..2693282b48a 100644 --- a/tools/benchmark-core/benches/vnode.rs +++ b/tools/benchmark-core/benches/vnode.rs @@ -11,7 +11,7 @@ fn Stuff(_: &()) -> Html { } } -#[divan::bench] +#[divan::bench(sample_size = 10000000)] fn vnode_clone(bencher: divan::Bencher) { let html = html! {
From 45b2add2d5de68d3e3314d3655ca038cca748f59 Mon Sep 17 00:00:00 2001 From: Cecile Tonglet Date: Wed, 18 Oct 2023 16:52:23 +0200 Subject: [PATCH 15/28] WIP --- .github/workflows/benchmark-core.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/benchmark-core.yml b/.github/workflows/benchmark-core.yml index ef821f20ed5..265e20ebe3a 100644 --- a/.github/workflows/benchmark-core.yml +++ b/.github/workflows/benchmark-core.yml @@ -1,5 +1,5 @@ --- -name: Benchmark - SSR +name: Benchmark - core on: pull_request: @@ -49,8 +49,11 @@ jobs: working-directory: current-pr/tools/benchmark-core - name: Run master benchmark - run: cargo bench -q > ../output.log + run: | + touch ../output.log + cargo bench -q > ../output.log working-directory: yew-master/tools/benchmark-core + continue-on-error: true - name: Write Pull Request ID run: | From 0365c759470c2ab61a37673d5c8d8a9114208382 Mon Sep 17 00:00:00 2001 From: Cecile Tonglet Date: Wed, 18 Oct 2023 16:54:57 +0200 Subject: [PATCH 16/28] WIP --- .github/workflows/benchmark-core.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/benchmark-core.yml b/.github/workflows/benchmark-core.yml index 265e20ebe3a..35189a67f20 100644 --- a/.github/workflows/benchmark-core.yml +++ b/.github/workflows/benchmark-core.yml @@ -50,9 +50,9 @@ jobs: - name: Run master benchmark run: | + cd yew-master/tools/benchmark-core touch ../output.log cargo bench -q > ../output.log - working-directory: yew-master/tools/benchmark-core continue-on-error: true - name: Write Pull Request ID From 805e50412b8817d12ce20cdd339624e297292b7f Mon Sep 17 00:00:00 2001 From: Cecile Tonglet Date: Wed, 18 Oct 2023 17:00:29 +0200 Subject: [PATCH 17/28] WIP --- .github/workflows/benchmark-core.yml | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/.github/workflows/benchmark-core.yml b/.github/workflows/benchmark-core.yml index 35189a67f20..1c1f920068b 100644 --- a/.github/workflows/benchmark-core.yml +++ b/.github/workflows/benchmark-core.yml @@ -49,11 +49,16 @@ jobs: working-directory: current-pr/tools/benchmark-core - name: Run master benchmark - run: | - cd yew-master/tools/benchmark-core - touch ../output.log - cargo bench -q > ../output.log + run: cargo bench -q > ../output.log continue-on-error: true + with: + working-directory: yew-master/tools/benchmark-core + + - name: Ignore master benchmark + run: touch ../output.log + if: failure() + with: + working-directory: yew-master/tools/benchmark-core - name: Write Pull Request ID run: | From 4e1e727a9b45ffdac61925db7c22a6348304560e Mon Sep 17 00:00:00 2001 From: Cecile Tonglet Date: Wed, 18 Oct 2023 17:02:15 +0200 Subject: [PATCH 18/28] WIP --- .github/workflows/benchmark-core.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/benchmark-core.yml b/.github/workflows/benchmark-core.yml index 1c1f920068b..677c2d0a5dd 100644 --- a/.github/workflows/benchmark-core.yml +++ b/.github/workflows/benchmark-core.yml @@ -51,14 +51,12 @@ jobs: - name: Run master benchmark run: cargo bench -q > ../output.log continue-on-error: true - with: - working-directory: yew-master/tools/benchmark-core + working-directory: yew-master/tools/benchmark-core - name: Ignore master benchmark run: touch ../output.log if: failure() - with: - working-directory: yew-master/tools/benchmark-core + working-directory: yew-master/tools/benchmark-core - name: Write Pull Request ID run: | From a1f2df99c60828adf330e7b530c0c2a254d5c007 Mon Sep 17 00:00:00 2001 From: Cecile Tonglet Date: Wed, 18 Oct 2023 17:04:17 +0200 Subject: [PATCH 19/28] WIP --- .github/workflows/benchmark-core.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/benchmark-core.yml b/.github/workflows/benchmark-core.yml index 677c2d0a5dd..7f70876bd47 100644 --- a/.github/workflows/benchmark-core.yml +++ b/.github/workflows/benchmark-core.yml @@ -54,9 +54,8 @@ jobs: working-directory: yew-master/tools/benchmark-core - name: Ignore master benchmark - run: touch ../output.log + run: touch yew-master/tools/output.log if: failure() - working-directory: yew-master/tools/benchmark-core - name: Write Pull Request ID run: | From befcaa2235dcbc3a3584d5253a294bb834bbe5c6 Mon Sep 17 00:00:00 2001 From: Cecile Tonglet Date: Wed, 18 Oct 2023 17:05:34 +0200 Subject: [PATCH 20/28] WIP --- .github/workflows/benchmark-core.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/benchmark-core.yml b/.github/workflows/benchmark-core.yml index 7f70876bd47..f7e180c6ade 100644 --- a/.github/workflows/benchmark-core.yml +++ b/.github/workflows/benchmark-core.yml @@ -55,7 +55,6 @@ jobs: - name: Ignore master benchmark run: touch yew-master/tools/output.log - if: failure() - name: Write Pull Request ID run: | From e0711b135be96fa2db5f2aee8e2c2c6653c62552 Mon Sep 17 00:00:00 2001 From: Cecile Tonglet Date: Wed, 18 Oct 2023 17:57:30 +0200 Subject: [PATCH 21/28] WIP --- .github/workflows/benchmark-core.yml | 91 ++++++++++++++++++++ .github/workflows/post-benchmark-core.yml | 100 ---------------------- 2 files changed, 91 insertions(+), 100 deletions(-) delete mode 100644 .github/workflows/post-benchmark-core.yml diff --git a/.github/workflows/benchmark-core.yml b/.github/workflows/benchmark-core.yml index f7e180c6ade..339f48bb3b5 100644 --- a/.github/workflows/benchmark-core.yml +++ b/.github/workflows/benchmark-core.yml @@ -69,3 +69,94 @@ jobs: yew-master/tools/output.log current-pr/tools/output.log retention-days: 1 + + post-benchmark-core: + name: Post Comment on Pull Request + runs-on: ubuntu-latest + needs: benchmark-core + + steps: + - name: Download Repository + uses: actions/checkout@v3 + + - name: Download Artifact + uses: Legit-Labs/action-download-artifact@v2 + with: + github_token: "${{ secrets.GITHUB_TOKEN }}" + workflow: benchmark-core.yml + run_id: ${{ github.event.workflow_run.id }} + name: benchmark-core + path: "benchmark-core/" + + - name: Make pull request comment + run: | + cat - >>comment.txt <>comment.txt + cat - >>comment.txt <> comment.txt + ``` + EOF + cat benchmark-core/current-pr/tools/output.json >>comment.txt + cat - >>comment.txt <> $GITHUB_ENV + + - name: Post Comment + uses: actions/github-script@v6 + with: + script: | + const fs = require('fs'); + + const commentInfo = { + ...context.repo, + issue_number: ${{ env.PR_NUMBER }}, + }; + + const comment = { + ...commentInfo, + body: fs.readFileSync("comment.txt", 'utf-8'), + }; + + function isCommentByBot(comment) { + return comment.user.type === "Bot" && comment.body.includes("### Benchmark - core"); + } + + let commentId = null; + const comments = (await github.rest.issues.listComments(commentInfo)).data; + for (let i = comments.length; i--; ) { + const c = comments[i]; + if (isCommentByBot(c)) { + commentId = c.id; + break; + } + } + + if (commentId) { + try { + await github.rest.issues.updateComment({ + ...context.repo, + comment_id: commentId, + body: comment.body, + }); + } catch (e) { + commentId = null; + } + } + + if (!commentId) { + await github.rest.issues.createComment(comment); + } diff --git a/.github/workflows/post-benchmark-core.yml b/.github/workflows/post-benchmark-core.yml deleted file mode 100644 index ff011542164..00000000000 --- a/.github/workflows/post-benchmark-core.yml +++ /dev/null @@ -1,100 +0,0 @@ ---- -name: Post Comment for Benchmark - core - -on: - workflow_run: - workflows: ["Benchmark - core"] - types: - - completed - -jobs: - post-benchmark-core: - if: github.event.workflow_run.event == 'pull_request' - name: Post Comment on Pull Request - runs-on: ubuntu-latest - - steps: - - name: Download Repository - uses: actions/checkout@v3 - - - name: Download Artifact - uses: Legit-Labs/action-download-artifact@v2 - with: - github_token: "${{ secrets.GITHUB_TOKEN }}" - workflow: benchmark-core.yml - run_id: ${{ github.event.workflow_run.id }} - name: benchmark-core - path: "benchmark-core/" - - - name: Make pull request comment - run: | - cat - >>comment.txt <>comment.txt - cat - >>comment.txt <> comment.txt - ``` - EOF - cat benchmark-core/current-pr/tools/output.json >>comment.txt - cat - >>comment.txt <> $GITHUB_ENV - - - name: Post Comment - uses: actions/github-script@v6 - with: - script: | - const fs = require('fs'); - - const commentInfo = { - ...context.repo, - issue_number: ${{ env.PR_NUMBER }}, - }; - - const comment = { - ...commentInfo, - body: fs.readFileSync("comment.txt", 'utf-8'), - }; - - function isCommentByBot(comment) { - return comment.user.type === "Bot" && comment.body.includes("### Benchmark - core"); - } - - let commentId = null; - const comments = (await github.rest.issues.listComments(commentInfo)).data; - for (let i = comments.length; i--; ) { - const c = comments[i]; - if (isCommentByBot(c)) { - commentId = c.id; - break; - } - } - - if (commentId) { - try { - await github.rest.issues.updateComment({ - ...context.repo, - comment_id: commentId, - body: comment.body, - }); - } catch (e) { - commentId = null; - } - } - - if (!commentId) { - await github.rest.issues.createComment(comment); - } From 716b0095159ad3f88cadc4297681a3e32b348b37 Mon Sep 17 00:00:00 2001 From: Cecile Tonglet Date: Wed, 18 Oct 2023 18:00:43 +0200 Subject: [PATCH 22/28] WIP --- .github/workflows/benchmark-core.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/benchmark-core.yml b/.github/workflows/benchmark-core.yml index 339f48bb3b5..024414ad398 100644 --- a/.github/workflows/benchmark-core.yml +++ b/.github/workflows/benchmark-core.yml @@ -53,7 +53,7 @@ jobs: continue-on-error: true working-directory: yew-master/tools/benchmark-core - - name: Ignore master benchmark + - name: Make sure master's output log exists run: touch yew-master/tools/output.log - name: Write Pull Request ID @@ -93,17 +93,17 @@ jobs: cat - >>comment.txt <>comment.txt cat - >>comment.txt <> comment.txt - ``` + \`\`\` EOF cat benchmark-core/current-pr/tools/output.json >>comment.txt cat - >>comment.txt < Date: Wed, 18 Oct 2023 18:05:35 +0200 Subject: [PATCH 23/28] WIP --- .github/workflows/benchmark-core.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/benchmark-core.yml b/.github/workflows/benchmark-core.yml index 024414ad398..53a04870ad2 100644 --- a/.github/workflows/benchmark-core.yml +++ b/.github/workflows/benchmark-core.yml @@ -83,8 +83,6 @@ jobs: uses: Legit-Labs/action-download-artifact@v2 with: github_token: "${{ secrets.GITHUB_TOKEN }}" - workflow: benchmark-core.yml - run_id: ${{ github.event.workflow_run.id }} name: benchmark-core path: "benchmark-core/" @@ -95,13 +93,13 @@ jobs: #### Yew Master \`\`\` EOF - cat benchmark-core/yew-master/tools/output.json >>comment.txt + cat benchmark-core/yew-master/tools/output.log >>comment.txt cat - >>comment.txt <> comment.txt \`\`\` EOF - cat benchmark-core/current-pr/tools/output.json >>comment.txt + cat benchmark-core/current-pr/tools/output.log >>comment.txt cat - >>comment.txt < Date: Wed, 18 Oct 2023 18:43:39 +0200 Subject: [PATCH 24/28] WIP --- .github/workflows/benchmark-core.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/benchmark-core.yml b/.github/workflows/benchmark-core.yml index 53a04870ad2..6c028c2f8ce 100644 --- a/.github/workflows/benchmark-core.yml +++ b/.github/workflows/benchmark-core.yml @@ -83,6 +83,7 @@ jobs: uses: Legit-Labs/action-download-artifact@v2 with: github_token: "${{ secrets.GITHUB_TOKEN }}" + workflow: benchmark-core.yml name: benchmark-core path: "benchmark-core/" From 8804b0f4fd57d61e592ea27631db1376b3971f62 Mon Sep 17 00:00:00 2001 From: Cecile Tonglet Date: Tue, 24 Oct 2023 10:53:47 +0200 Subject: [PATCH 25/28] Use the 2 workflows approach, will fix after merge if not working --- .github/workflows/benchmark-core.yml | 90 ------------------- .github/workflows/post-benchmark-core.yml | 100 ++++++++++++++++++++++ 2 files changed, 100 insertions(+), 90 deletions(-) create mode 100644 .github/workflows/post-benchmark-core.yml diff --git a/.github/workflows/benchmark-core.yml b/.github/workflows/benchmark-core.yml index 6c028c2f8ce..f9277e4c385 100644 --- a/.github/workflows/benchmark-core.yml +++ b/.github/workflows/benchmark-core.yml @@ -69,93 +69,3 @@ jobs: yew-master/tools/output.log current-pr/tools/output.log retention-days: 1 - - post-benchmark-core: - name: Post Comment on Pull Request - runs-on: ubuntu-latest - needs: benchmark-core - - steps: - - name: Download Repository - uses: actions/checkout@v3 - - - name: Download Artifact - uses: Legit-Labs/action-download-artifact@v2 - with: - github_token: "${{ secrets.GITHUB_TOKEN }}" - workflow: benchmark-core.yml - name: benchmark-core - path: "benchmark-core/" - - - name: Make pull request comment - run: | - cat - >>comment.txt <>comment.txt - cat - >>comment.txt <> comment.txt - \`\`\` - EOF - cat benchmark-core/current-pr/tools/output.log >>comment.txt - cat - >>comment.txt <> $GITHUB_ENV - - - name: Post Comment - uses: actions/github-script@v6 - with: - script: | - const fs = require('fs'); - - const commentInfo = { - ...context.repo, - issue_number: ${{ env.PR_NUMBER }}, - }; - - const comment = { - ...commentInfo, - body: fs.readFileSync("comment.txt", 'utf-8'), - }; - - function isCommentByBot(comment) { - return comment.user.type === "Bot" && comment.body.includes("### Benchmark - core"); - } - - let commentId = null; - const comments = (await github.rest.issues.listComments(commentInfo)).data; - for (let i = comments.length; i--; ) { - const c = comments[i]; - if (isCommentByBot(c)) { - commentId = c.id; - break; - } - } - - if (commentId) { - try { - await github.rest.issues.updateComment({ - ...context.repo, - comment_id: commentId, - body: comment.body, - }); - } catch (e) { - commentId = null; - } - } - - if (!commentId) { - await github.rest.issues.createComment(comment); - } diff --git a/.github/workflows/post-benchmark-core.yml b/.github/workflows/post-benchmark-core.yml new file mode 100644 index 00000000000..ff011542164 --- /dev/null +++ b/.github/workflows/post-benchmark-core.yml @@ -0,0 +1,100 @@ +--- +name: Post Comment for Benchmark - core + +on: + workflow_run: + workflows: ["Benchmark - core"] + types: + - completed + +jobs: + post-benchmark-core: + if: github.event.workflow_run.event == 'pull_request' + name: Post Comment on Pull Request + runs-on: ubuntu-latest + + steps: + - name: Download Repository + uses: actions/checkout@v3 + + - name: Download Artifact + uses: Legit-Labs/action-download-artifact@v2 + with: + github_token: "${{ secrets.GITHUB_TOKEN }}" + workflow: benchmark-core.yml + run_id: ${{ github.event.workflow_run.id }} + name: benchmark-core + path: "benchmark-core/" + + - name: Make pull request comment + run: | + cat - >>comment.txt <>comment.txt + cat - >>comment.txt <> comment.txt + ``` + EOF + cat benchmark-core/current-pr/tools/output.json >>comment.txt + cat - >>comment.txt <> $GITHUB_ENV + + - name: Post Comment + uses: actions/github-script@v6 + with: + script: | + const fs = require('fs'); + + const commentInfo = { + ...context.repo, + issue_number: ${{ env.PR_NUMBER }}, + }; + + const comment = { + ...commentInfo, + body: fs.readFileSync("comment.txt", 'utf-8'), + }; + + function isCommentByBot(comment) { + return comment.user.type === "Bot" && comment.body.includes("### Benchmark - core"); + } + + let commentId = null; + const comments = (await github.rest.issues.listComments(commentInfo)).data; + for (let i = comments.length; i--; ) { + const c = comments[i]; + if (isCommentByBot(c)) { + commentId = c.id; + break; + } + } + + if (commentId) { + try { + await github.rest.issues.updateComment({ + ...context.repo, + comment_id: commentId, + body: comment.body, + }); + } catch (e) { + commentId = null; + } + } + + if (!commentId) { + await github.rest.issues.createComment(comment); + } From 1e8c819ae0b4d18a8bd5e232b819d88f703c4214 Mon Sep 17 00:00:00 2001 From: Cecile Tonglet Date: Fri, 27 Oct 2023 14:28:10 +0200 Subject: [PATCH 26/28] CLEANUP --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 97915e885bc..a78f6e8976f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -709,7 +709,7 @@ checksum = "b6e12f661a0897d97d90d5f4d2c441ad947c560863b0e093b19dd8b309a1326c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -1755,7 +1755,7 @@ checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" dependencies = [ "hermit-abi 0.3.1", "io-lifetimes", - "rustix 0.37.20", + "rustix 0.37.25", "windows-sys 0.48.0", ] @@ -1934,7 +1934,7 @@ checksum = "ba125974b109d512fccbc6c0244e7580143e460895dfd6ea7f8bbb692fd94396" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -2973,7 +2973,7 @@ dependencies = [ "cfg-if", "fastrand", "redox_syscall", - "rustix 0.37.20", + "rustix 0.37.25", "windows-sys 0.48.0", ] From 5bd102b0cba45bf88c77be856cad223f0968d394 Mon Sep 17 00:00:00 2001 From: Cecile Tonglet Date: Fri, 27 Oct 2023 14:45:56 +0200 Subject: [PATCH 27/28] can i push that change here pretty please --- .github/workflows/post-benchmark-core.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/post-benchmark-core.yml b/.github/workflows/post-benchmark-core.yml index d5567375f56..635f67f5475 100644 --- a/.github/workflows/post-benchmark-core.yml +++ b/.github/workflows/post-benchmark-core.yml @@ -33,13 +33,13 @@ jobs: #### Yew Master \`\`\` EOF - cat benchmark-core/yew-master/tools/output.json >>comment.txt + cat benchmark-core/yew-master/tools/output.log >>comment.txt cat - >>comment.txt <> comment.txt \`\`\` EOF - cat benchmark-core/current-pr/tools/output.json >>comment.txt + cat benchmark-core/current-pr/tools/output.log >>comment.txt cat - >>comment.txt < Date: Fri, 27 Oct 2023 15:53:19 +0200 Subject: [PATCH 28/28] Trigger CI