fix: get rollover working

This commit is contained in:
Jonathan Kelley 2022-12-13 14:44:47 -08:00
parent 79e786aca5
commit 5c20e651da
7 changed files with 61 additions and 25 deletions

View file

@ -57,6 +57,7 @@ reqwest = { version = "0.11.9", features = ["json"] }
fern = { version = "0.6.0", features = ["colored"] } fern = { version = "0.6.0", features = ["colored"] }
thiserror = "1.0.30" thiserror = "1.0.30"
env_logger = "0.9.0" env_logger = "0.9.0"
simple_logger = "4.0.0"
[profile.release] [profile.release]
opt-level = 3 opt-level = 3

View file

@ -20,6 +20,9 @@ fn app(cx: Scope) -> Element {
Link { to: "/blog", li { "blog" } } Link { to: "/blog", li { "blog" } }
Link { to: "/blog/tim", li { "tims' blog" } } Link { to: "/blog/tim", li { "tims' blog" } }
Link { to: "/blog/bill", li { "bills' blog" } } Link { to: "/blog/bill", li { "bills' blog" } }
Link { to: "/blog/james",
li { "james amazing' blog" }
}
Link { to: "/apples", li { "go to apples" } } Link { to: "/apples", li { "go to apples" } }
} }
Route { to: "/", Home {} } Route { to: "/", Home {} }
@ -42,11 +45,17 @@ fn BlogList(cx: Scope) -> Element {
} }
fn BlogPost(cx: Scope) -> Element { fn BlogPost(cx: Scope) -> Element {
let Some(id) = use_route(cx).segment("id") else { let Some(id) = use_route(cx).segment("id") else {
return cx.render(rsx! { div { "No blog post id" } }) return cx.render(rsx! { div { "No blog post id" } })
}; };
log::debug!("rendering 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" }
}
})
} }

View file

@ -36,6 +36,7 @@ serde = { version = "1", features = ["derive"], optional = true }
anyhow = "1.0.66" anyhow = "1.0.66"
smallbox = "0.8.1" smallbox = "0.8.1"
log = "0.4.17"
[dev-dependencies] [dev-dependencies]
tokio = { version = "*", features = ["full"] } tokio = { version = "*", features = ["full"] }

View file

@ -108,9 +108,10 @@ impl VirtualDom {
}); });
for root in node.root_ids { for root in node.root_ids {
let id = root.get().unwrap(); if let Some(id) = root.get() {
if id.0 != 0 { if id.0 != 0 {
self.try_reclaim(id); self.try_reclaim(id);
}
} }
} }
} }
@ -131,7 +132,9 @@ impl VirtualDom {
node.dynamic_nodes.iter().for_each(|child| match child { node.dynamic_nodes.iter().for_each(|child| match child {
// Only descend if the props are borrowed // Only descend if the props are borrowed
DynamicNode::Component(c) if !c.static_props => { 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(); c.props.take();
} }

View file

@ -113,7 +113,7 @@ impl<'b> VirtualDom {
idx: usize, idx: usize,
) { ) {
match (left_node, right_node) { 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), (Fragment(left), Fragment(right)) => self.diff_non_empty_fragment(left, right),
(Placeholder(left), Placeholder(right)) => right.id.set(left.id.get()), (Placeholder(left), Placeholder(right)) => right.id.set(left.id.get()),
(Component(left), Component(right)) => self.diff_vcomponent(left, right, node, idx), (Component(left), Component(right)) => self.diff_vcomponent(left, right, node, idx),
@ -174,6 +174,10 @@ impl<'b> VirtualDom {
right_template: &'b VNode<'b>, right_template: &'b VNode<'b>,
idx: usize, idx: usize,
) { ) {
if std::ptr::eq(left, right) {
return;
}
// Replace components that have different render fns // Replace components that have different render fns
if left.render_fn != right.render_fn { if left.render_fn != right.render_fn {
let created = self.create_component_node(right_template, right, idx); 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 // 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)); 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>) { fn light_diff_templates(&mut self, left: &'b VNode<'b>, right: &'b VNode<'b>) {
match matching_components(left, right) { self.replace(left, right)
None => self.replace(left, right), // match matching_components(left, right) {
Some(components) => components // None => self.replace(left, right),
.into_iter() // Some(components) => components
.enumerate() // .into_iter()
.for_each(|(idx, (l, r))| self.diff_vcomponent(l, r, right, idx)), // .enumerate()
} // .for_each(|(idx, (l, r))| self.diff_vcomponent(l, r, right, idx)),
// }
} }
/// Diff the two text nodes /// 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 /// 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. /// different.
fn diff_vtext(&mut self, left: &'b VText<'b>, right: &'b VText<'b>) { fn diff_vtext(&mut self, left: &'b VText<'b>, right: &'b VText<'b>, node: &'b VNode<'b>) {
let id = left.id.get().unwrap(); let id = left
.id
.get()
.unwrap_or_else(|| self.next_element(node, &[0]));
right.id.set(Some(id)); right.id.set(Some(id));
if left.value != right.value { if left.value != right.value {
let value = unsafe { std::mem::transmute(right.value) }; let value = unsafe { std::mem::transmute(right.value) };
@ -327,11 +345,12 @@ impl<'b> VirtualDom {
match dyn_node { match dyn_node {
Component(comp) => { Component(comp) => {
let scope = comp.scope.take().unwrap(); if let Some(scope) = comp.scope.take() {
match unsafe { self.scopes[scope.0].root_node().extend_lifetime_ref() } { match unsafe { self.scopes[scope.0].root_node().extend_lifetime_ref() } {
RenderReturn::Sync(Ok(t)) => self.clean_up_node(t), RenderReturn::Sync(Ok(t)) => self.clean_up_node(t),
_ => todo!("cannot handle nonstandard nodes"), _ => todo!("cannot handle nonstandard nodes"),
}; };
}
} }
Text(t) => { Text(t) => {
if let Some(id) = t.id.take() { if let Some(id) = t.id.take() {

View file

@ -520,7 +520,6 @@ impl VirtualDom {
pin_mut!(deadline); pin_mut!(deadline);
self.process_events(); self.process_events();
println!("rendering with dirty scopes {:#?}", self.dirty_scopes);
loop { loop {
// first, unload any complete suspense trees // first, unload any complete suspense trees
@ -548,8 +547,6 @@ impl VirtualDom {
if let Some(dirty) = self.dirty_scopes.iter().next().cloned() { if let Some(dirty) = self.dirty_scopes.iter().next().cloned() {
self.dirty_scopes.remove(&dirty); 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 the scope is currently suspended, then we should skip it, ignoring any tasks calling for an update
if self.is_scope_suspended(dirty.id) { if self.is_scope_suspended(dirty.id) {
continue; continue;

View file

@ -16,6 +16,7 @@ fn app(cx: Scope) -> Element {
Link { to: "/blog", li { "blog" } } Link { to: "/blog", li { "blog" } }
Link { to: "/blog/tim", li { "tims' blog" } } Link { to: "/blog/tim", li { "tims' blog" } }
Link { to: "/blog/bill", li { "bills' blog" } } Link { to: "/blog/bill", li { "bills' blog" } }
Link { to: "/blog/james", li { "james amazing' blog" } }
Link { to: "/apples", li { "go to apples" } } Link { to: "/apples", li { "go to apples" } }
} }
Route { to: "/", Home {} } Route { to: "/", Home {} }
@ -42,5 +43,10 @@ fn BlogPost(cx: Scope) -> Element {
log::trace!("rendering blog post {}", id); 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" }
}
})
} }