Skip to content

Commit

Permalink
Change access to VList children to a wrapper (#2673)
Browse files Browse the repository at this point in the history
this should avoid having to manually call recheck_fully_keyed

* add mutable accessor to children
* fix workflow
* fix markdown example
* remove recheck_fully_keyed
  • Loading branch information
WorldSEnder committed May 11, 2022
1 parent 3760c5f commit d7b43bb
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 31 deletions.
41 changes: 22 additions & 19 deletions examples/futures/src/markdown.rs
Expand Up @@ -53,31 +53,34 @@ pub fn render_markdown(src: &str) -> Html {
pre.add_child(top.into());
top = pre;
} else if let Tag::Table(aligns) = tag {
for r in top.children_mut().iter_mut().flat_map(|ch| ch.iter_mut()) {
if let VNode::VTag(ref mut vtag) = r {
for (i, c) in vtag
.children_mut()
.iter_mut()
.flat_map(|ch| ch.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"),
if let Some(top_children) = top.children_mut() {
for r in top_children.children_mut().iter_mut() {
if let VNode::VTag(ref mut vtag) = r {
if let Some(vtag_children) = vtag.children_mut() {
for (i, c) in
vtag_children.children_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"),
}
}
}
}
}
}
}
} else if let Tag::TableHead = tag {
for c in top.children_mut().iter_mut().flat_map(|ch| ch.iter_mut()) {
if let VNode::VTag(ref mut vtag) = c {
// TODO
// vtag.tag = "th".into();
vtag.add_attribute("scope", "col");
if let Some(top_children) = top.children_mut() {
for c in top_children.children_mut().iter_mut() {
if let VNode::VTag(ref mut vtag) = c {
// TODO
// vtag.tag = "th".into();
vtag.add_attribute("scope", "col");
}
}
}
}
Expand Down
81 changes: 70 additions & 11 deletions packages/yew/src/virtual_dom/vlist.rs
Expand Up @@ -29,13 +29,42 @@ impl Deref for VList {
}
}

impl DerefMut for VList {
/// Mutable children of a [VList].
///
/// This struct has a `DerefMut` implementations into [`Vec<VNode>`](std::vec::Vec).
/// Prefer to use immutable access, since this re-checks if all nodes have keys when dropped.
pub struct ChildrenMut<'a> {
children: &'a mut Vec<VNode>,
fully_keyed: &'a mut bool,
}

impl<'a> Deref for ChildrenMut<'a> {
type Target = Vec<VNode>;

fn deref(&self) -> &Self::Target {
self.children
}
}

impl<'a> DerefMut for ChildrenMut<'a> {
fn deref_mut(&mut self) -> &mut Self::Target {
// Caller might change the keys of the VList or add unkeyed children.
// Defensively assume they will.
self.fully_keyed = false;
*self.fully_keyed = false;
self.children
}
}

&mut self.children
impl<'a> Drop for ChildrenMut<'a> {
fn drop(&mut self) {
if !*self.fully_keyed {
// Caller might have changed the keys of the VList or add unkeyed children.
*self.fully_keyed = self.children.iter().all(|ch| ch.has_key());
}
}
}

impl<'a> std::fmt::Debug for ChildrenMut<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("ChildrenMut").field(&self.children).finish()
}
}

Expand Down Expand Up @@ -76,12 +105,42 @@ impl VList {
}
}

/// Recheck, if the all the children have keys.
///
/// Run this, after modifying the child list that contained only keyed children prior to the
/// mutable dereference.
pub fn recheck_fully_keyed(&mut self) {
self.fully_keyed = self.children.iter().all(|ch| ch.has_key());
/// Get a mutable list of children in this vlist.
pub fn children_mut(&mut self) -> ChildrenMut<'_> {
ChildrenMut {
children: &mut self.children,
fully_keyed: &mut self.fully_keyed,
}
}
}

#[cfg(test)]
mod test {
use super::*;
use crate::virtual_dom::{VTag, VText};

#[test]
fn mutably_change_children() {
let mut vlist = VList::new();
assert!(vlist.fully_keyed, "should start fully keyed");
// add a child that is keyed
let mut children = vlist.children_mut();
children.push(VNode::VTag({
let mut tag = VTag::new("a");
tag.key = Some(42u32.into());
Box::new(tag)
}));
drop(children);
assert!(vlist.fully_keyed, "should still be fully keyed");
assert_eq!(vlist.len(), 1, "should contain 1 child");
// now add a child that is not keyed
let mut children = vlist.children_mut();
children.push(VNode::VText(VText::new("lorem ipsum")));
drop(children);
assert!(
!vlist.fully_keyed,
"should not be fully keyed, text tags have no key"
);
}
}

Expand Down
2 changes: 1 addition & 1 deletion tools/changelog/Cargo.toml
Expand Up @@ -9,7 +9,7 @@ edition = "2021"
[dependencies]
anyhow = "1"
chrono = "0.4"
git2 = "0.14"
git2 = "=0.14.2" # see https://github.com/rust-lang/git2-rs/issues/838 fixed with MSRV 1.60
regex = "1"
reqwest = { version = "0.11", features = ["blocking", "json"] }
serde = { version = "1", features = ["derive"] }
Expand Down

1 comment on commit d7b43bb

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yew master branch benchmarks (Lower is better)

Benchmark suite Current: d7b43bb Previous: 3760c5f Ratio
yew-struct-keyed 01_run1k 174.5125 159.72500000000002 1.09
yew-struct-keyed 02_replace1k 174.724 163.327 1.07
yew-struct-keyed 03_update10th1k_x16 368.992 249.5885 1.48
yew-struct-keyed 04_select1k 63.722 41.0075 1.55
yew-struct-keyed 05_swap1k 85.703 65.4005 1.31
yew-struct-keyed 06_remove-one-1k 27.4775 23.472 1.17
yew-struct-keyed 07_create10k 2945.41 2650.714 1.11
yew-struct-keyed 08_create1k-after1k_x2 398.424 353.8735 1.13
yew-struct-keyed 09_clear1k_x8 181.215 149.8995 1.21
yew-struct-keyed 21_ready-memory 1.4553108215332031 1.459808349609375 1.00
yew-struct-keyed 22_run-memory 1.6642837524414062 1.660259246826172 1.00
yew-struct-keyed 23_update5-memory 1.7007789611816406 1.699298858642578 1.00
yew-struct-keyed 24_run5-memory 1.7175369262695312 1.7175369262695312 1
yew-struct-keyed 25_run-clear-memory 1.332073211669922 1.4279136657714844 0.93
yew-struct-keyed 31_startup-ci 1882.71 1731.044 1.09
yew-struct-keyed 32_startup-bt 30.888 23.427999999999997 1.32
yew-struct-keyed 33_startup-mainthreadcost 239.18000000000004 202.692 1.18
yew-struct-keyed 34_startup-totalbytes 328.7421875 328.7373046875 1.00

This comment was automatically generated by workflow using github-action-benchmark.

Please sign in to comment.