From 5c20e651da3153e1a507b57b3db8c0f1bcb7639d Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Tue, 13 Dec 2022 14:44:47 -0800 Subject: [PATCH] fix: get rollover working --- Cargo.toml | 1 + .../examples => examples}/simple_desktop.rs | 11 +++- packages/core/Cargo.toml | 1 + packages/core/src/arena.rs | 11 ++-- packages/core/src/diff.rs | 51 +++++++++++++------ packages/core/src/virtual_dom.rs | 3 -- packages/router/examples/simple.rs | 8 ++- 7 files changed, 61 insertions(+), 25 deletions(-) rename {packages/router/examples => examples}/simple_desktop.rs (85%) diff --git a/Cargo.toml b/Cargo.toml index 11ea7546b..8f3a33d96 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -57,6 +57,7 @@ reqwest = { version = "0.11.9", features = ["json"] } fern = { version = "0.6.0", features = ["colored"] } thiserror = "1.0.30" env_logger = "0.9.0" +simple_logger = "4.0.0" [profile.release] opt-level = 3 diff --git a/packages/router/examples/simple_desktop.rs b/examples/simple_desktop.rs similarity index 85% rename from packages/router/examples/simple_desktop.rs rename to examples/simple_desktop.rs index 2c0ec1de5..afe4664fe 100644 --- a/packages/router/examples/simple_desktop.rs +++ b/examples/simple_desktop.rs @@ -20,6 +20,9 @@ fn app(cx: Scope) -> Element { Link { to: "/blog", li { "blog" } } Link { to: "/blog/tim", li { "tims' blog" } } Link { to: "/blog/bill", li { "bills' blog" } } + Link { to: "/blog/james", + li { "james amazing' blog" } + } Link { to: "/apples", li { "go to apples" } } } Route { to: "/", Home {} } @@ -42,11 +45,17 @@ fn BlogList(cx: Scope) -> Element { } fn BlogPost(cx: Scope) -> Element { + let Some(id) = use_route(cx).segment("id") else { return cx.render(rsx! { div { "No blog post id" } }) }; log::debug!("rendering blog post {}", id); - cx.render(rsx! { div { "{id:?}" } }) + cx.render(rsx! { + div { + h3 { "blog post: {id:?}" } + Link { to: "/blog/", "back to blog list" } + } + }) } diff --git a/packages/core/Cargo.toml b/packages/core/Cargo.toml index 37f78f04d..03c120301 100644 --- a/packages/core/Cargo.toml +++ b/packages/core/Cargo.toml @@ -36,6 +36,7 @@ serde = { version = "1", features = ["derive"], optional = true } anyhow = "1.0.66" smallbox = "0.8.1" +log = "0.4.17" [dev-dependencies] tokio = { version = "*", features = ["full"] } diff --git a/packages/core/src/arena.rs b/packages/core/src/arena.rs index 88642b0c2..055fba3c9 100644 --- a/packages/core/src/arena.rs +++ b/packages/core/src/arena.rs @@ -108,9 +108,10 @@ impl VirtualDom { }); for root in node.root_ids { - let id = root.get().unwrap(); - if id.0 != 0 { - self.try_reclaim(id); + if let Some(id) = root.get() { + if id.0 != 0 { + self.try_reclaim(id); + } } } } @@ -131,7 +132,9 @@ impl VirtualDom { node.dynamic_nodes.iter().for_each(|child| match child { // Only descend if the props are borrowed DynamicNode::Component(c) if !c.static_props => { - self.ensure_drop_safety(c.scope.get().unwrap()); + if let Some(scope) = c.scope.get() { + self.ensure_drop_safety(scope); + } c.props.take(); } diff --git a/packages/core/src/diff.rs b/packages/core/src/diff.rs index 1a8a9fcd7..504a0fe16 100644 --- a/packages/core/src/diff.rs +++ b/packages/core/src/diff.rs @@ -113,7 +113,7 @@ impl<'b> VirtualDom { idx: usize, ) { match (left_node, right_node) { - (Text(left), Text(right)) => self.diff_vtext(left, right), + (Text(left), Text(right)) => self.diff_vtext(left, right, node), (Fragment(left), Fragment(right)) => self.diff_non_empty_fragment(left, right), (Placeholder(left), Placeholder(right)) => right.id.set(left.id.get()), (Component(left), Component(right)) => self.diff_vcomponent(left, right, node, idx), @@ -174,6 +174,10 @@ impl<'b> VirtualDom { right_template: &'b VNode<'b>, idx: usize, ) { + if std::ptr::eq(left, right) { + return; + } + // Replace components that have different render fns if left.render_fn != right.render_fn { let created = self.create_component_node(right_template, right, idx); @@ -193,7 +197,16 @@ impl<'b> VirtualDom { } // Make sure the new vcomponent has the right scopeid associated to it - let scope_id = left.scope.get().unwrap(); + let Some(scope_id) = left.scope.get() else { + return; + }; + // let scope_id = left.scope.get().unwrap_or_else(|| { + // panic!( + // "A component should always have a scope associated to it. {:?}\n {:#?}", + // right.name, + // std::backtrace::Backtrace::force_capture() + // ) + // }); right.scope.set(Some(scope_id)); @@ -260,21 +273,26 @@ impl<'b> VirtualDom { /// } /// ``` fn light_diff_templates(&mut self, left: &'b VNode<'b>, right: &'b VNode<'b>) { - match matching_components(left, right) { - None => self.replace(left, right), - Some(components) => components - .into_iter() - .enumerate() - .for_each(|(idx, (l, r))| self.diff_vcomponent(l, r, right, idx)), - } + self.replace(left, right) + // match matching_components(left, right) { + // None => self.replace(left, right), + // Some(components) => components + // .into_iter() + // .enumerate() + // .for_each(|(idx, (l, r))| self.diff_vcomponent(l, r, right, idx)), + // } } /// Diff the two text nodes /// /// This just moves the ID of the old node over to the new node, and then sets the text of the new node if it's /// different. - fn diff_vtext(&mut self, left: &'b VText<'b>, right: &'b VText<'b>) { - let id = left.id.get().unwrap(); + fn diff_vtext(&mut self, left: &'b VText<'b>, right: &'b VText<'b>, node: &'b VNode<'b>) { + let id = left + .id + .get() + .unwrap_or_else(|| self.next_element(node, &[0])); + right.id.set(Some(id)); if left.value != right.value { let value = unsafe { std::mem::transmute(right.value) }; @@ -327,11 +345,12 @@ impl<'b> VirtualDom { match dyn_node { Component(comp) => { - let scope = comp.scope.take().unwrap(); - match unsafe { self.scopes[scope.0].root_node().extend_lifetime_ref() } { - RenderReturn::Sync(Ok(t)) => self.clean_up_node(t), - _ => todo!("cannot handle nonstandard nodes"), - }; + if let Some(scope) = comp.scope.take() { + match unsafe { self.scopes[scope.0].root_node().extend_lifetime_ref() } { + RenderReturn::Sync(Ok(t)) => self.clean_up_node(t), + _ => todo!("cannot handle nonstandard nodes"), + }; + } } Text(t) => { if let Some(id) = t.id.take() { diff --git a/packages/core/src/virtual_dom.rs b/packages/core/src/virtual_dom.rs index 35c7848f1..8b41ad951 100644 --- a/packages/core/src/virtual_dom.rs +++ b/packages/core/src/virtual_dom.rs @@ -520,7 +520,6 @@ impl VirtualDom { pin_mut!(deadline); self.process_events(); - println!("rendering with dirty scopes {:#?}", self.dirty_scopes); loop { // first, unload any complete suspense trees @@ -548,8 +547,6 @@ impl VirtualDom { if let Some(dirty) = self.dirty_scopes.iter().next().cloned() { self.dirty_scopes.remove(&dirty); - println!("diffing scope {:?}", dirty); - // if the scope is currently suspended, then we should skip it, ignoring any tasks calling for an update if self.is_scope_suspended(dirty.id) { continue; diff --git a/packages/router/examples/simple.rs b/packages/router/examples/simple.rs index 4c16c29a1..9b94c7a9d 100644 --- a/packages/router/examples/simple.rs +++ b/packages/router/examples/simple.rs @@ -16,6 +16,7 @@ fn app(cx: Scope) -> Element { Link { to: "/blog", li { "blog" } } Link { to: "/blog/tim", li { "tims' blog" } } Link { to: "/blog/bill", li { "bills' blog" } } + Link { to: "/blog/james", li { "james amazing' blog" } } Link { to: "/apples", li { "go to apples" } } } Route { to: "/", Home {} } @@ -42,5 +43,10 @@ fn BlogPost(cx: Scope) -> Element { log::trace!("rendering blog post {}", id); - cx.render(rsx! { div { "{id:?}" } }) + cx.render(rsx! { + div { + h3 { "blog post: {id:?}" } + Link { to: "/blog/", "back to blog list" } + } + }) }