handle abort diffing

This commit is contained in:
Evan Almloff 2023-01-07 19:01:29 -06:00
parent cb7e4f3f27
commit 927db9723a
2 changed files with 30 additions and 7 deletions

View file

@ -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();

View file

@ -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!(),