diff --git a/packages/core/src/arena.rs b/packages/core/src/arena.rs index a11fc69ba..4ffa5fe07 100644 --- a/packages/core/src/arena.rs +++ b/packages/core/src/arena.rs @@ -44,6 +44,14 @@ impl VirtualDom { self.next_reference(template, ElementPath::Root(path)) } + pub(crate) fn next_null(&mut self) -> ElementId { + let entry = self.elements.vacant_entry(); + let id = entry.key(); + + entry.insert(ElementRef::null()); + ElementId(id) + } + fn next_reference(&mut self, template: &VNode, path: ElementPath) -> ElementId { let entry = self.elements.vacant_entry(); let id = entry.key(); diff --git a/packages/core/src/diff.rs b/packages/core/src/diff.rs index 7227ee6e7..4617919cf 100644 --- a/packages/core/src/diff.rs +++ b/packages/core/src/diff.rs @@ -42,7 +42,7 @@ impl<'b> VirtualDom { // Just move over the placeholder (Aborted(l), Aborted(r)) => r.id.set(l.id.get()), - // Becomes async, do nothing while we ait + // Becomes async, do nothing while we wait (Ready(_nodes), Pending(_fut)) => self.diff_ok_to_async(_nodes, scope), // Placeholder becomes something @@ -65,8 +65,26 @@ impl<'b> VirtualDom { // } - fn diff_ok_to_err(&mut self, _l: &'b VNode<'b>, _p: &'b VPlaceholder) { - todo!() + fn diff_ok_to_err(&mut self, l: &'b VNode<'b>, p: &'b VPlaceholder) { + let id = self.next_null(); + p.id.set(Some(id)); + self.mutations.push(Mutation::CreatePlaceholder { id }); + + let pre_edits = self.mutations.edits.len(); + + self.remove_node(l, true); + + // We should always have a remove mutation + // Eventually we don't want to generate placeholders, so this might not be true. But it's true today + assert!(self.mutations.edits.len() > pre_edits); + + // We want to optimize the replace case to use one less mutation if possible + // Since mutations are done in reverse, the last node removed will be the first in the stack + // Instead of *just* removing it, we can use the replace mutation + match self.mutations.edits.pop().unwrap() { + Mutation::Remove { id } => self.mutations.push(Mutation::ReplaceWith { id, m: 1 }), + _ => panic!("Expected remove mutation from remove_node"), + }; } fn diff_node(&mut self, left_template: &'b VNode<'b>, right_template: &'b VNode<'b>) { @@ -905,10 +923,7 @@ impl<'b> VirtualDom { match unsafe { self.scopes[scope.0].root_node().extend_lifetime_ref() } { RenderReturn::Ready(t) => self.remove_node(t, gen_muts), - RenderReturn::Aborted(t) => { - if let Some(id) = t.id.get() { - self.try_reclaim(id); - } + RenderReturn::Aborted(_) => { return; } _ => todo!(),