feat: implement ID cycling
This commit is contained in:
1 parent
0cfbfc88e2
commit
5713e13ff2
10 files changed
+213
-145
No files matched your search
+86
-63
@@ -46,30 +46,29 @@ impl<'b: 'static> VirtualDom {
|
|||||||
fn diff_maybe_node(&mut self, left: &'b RenderReturn<'b>, right: &'b RenderReturn<'b>) {
|
fn diff_maybe_node(&mut self, left: &'b RenderReturn<'b>, right: &'b RenderReturn<'b>) {
|
||||||
use RenderReturn::{Async, Sync};
|
use RenderReturn::{Async, Sync};
|
||||||
match (left, right) {
|
match (left, right) {
|
||||||
// diff
|
|
||||||
(Sync(Ok(l)), Sync(Ok(r))) => self.diff_node(l, r),
|
(Sync(Ok(l)), Sync(Ok(r))) => self.diff_node(l, r),
|
||||||
|
|
||||||
_ => todo!("handle diffing nonstandard nodes"),
|
// Err cases
|
||||||
// // remove old with placeholder
|
(Sync(Ok(l)), Sync(Err(e))) => self.diff_ok_to_err(l, e),
|
||||||
// (Sync(Ok(l)), Sync(None)) | (Sync(Ok(l)), Async(_)) => {
|
(Sync(Err(e)), Sync(Ok(r))) => self.diff_err_to_ok(e, r),
|
||||||
// //
|
(Sync(Err(_eo)), Sync(Err(_en))) => { /* nothing */ }
|
||||||
// let id = self.next_element(l, &[]); // todo!
|
|
||||||
// m.push(Mutation::CreatePlaceholder { id });
|
|
||||||
// self.drop_template(m, l, true);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // remove placeholder with nodes
|
// Async
|
||||||
// (Sync(None), Sync(Ok(_))) => {}
|
(Sync(Ok(_l)), Async(_)) => todo!(),
|
||||||
// (Async(_), Sync(Ok(v))) => {}
|
(Sync(Err(_e)), Async(_)) => todo!(),
|
||||||
|
(Async(_), Sync(Ok(_r))) => todo!(),
|
||||||
// // nothing... just transfer the placeholders over
|
(Async(_), Sync(Err(_e))) => { /* nothing */ }
|
||||||
// (Async(_), Async(_))
|
(Async(_), Async(_)) => { /* nothing */ }
|
||||||
// | (Sync(None), Sync(None))
|
|
||||||
// | (Sync(None), Async(_))
|
|
||||||
// | (Async(_), Sync(None)) => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn diff_ok_to_err(&mut self, l: &'b VNode<'b>, e: &anyhow::Error) {
|
||||||
|
todo!("Not yet handling error rollover")
|
||||||
|
}
|
||||||
|
fn diff_err_to_ok(&mut self, e: &anyhow::Error, l: &'b VNode<'b>) {
|
||||||
|
todo!("Not yet handling error rollover")
|
||||||
|
}
|
||||||
|
|
||||||
pub fn diff_node(&mut self, left_template: &'b VNode<'b>, right_template: &'b VNode<'b>) {
|
pub fn diff_node(&mut self, left_template: &'b VNode<'b>, right_template: &'b VNode<'b>) {
|
||||||
if left_template.template.id != right_template.template.id {
|
if left_template.template.id != right_template.template.id {
|
||||||
return self.light_diff_templates(left_template, right_template);
|
return self.light_diff_templates(left_template, right_template);
|
||||||
@@ -97,7 +96,7 @@ impl<'b: 'static> VirtualDom {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
// todo: more types of attribute values
|
// todo: more types of attribute values
|
||||||
_ => (),
|
_ => todo!("other attribute types"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -111,7 +110,7 @@ impl<'b: 'static> VirtualDom {
|
|||||||
(Text(left), Text(right)) => self.diff_vtext(left, right),
|
(Text(left), Text(right)) => self.diff_vtext(left, right),
|
||||||
(Fragment(left), Fragment(right)) => self.diff_vfragment(left, right),
|
(Fragment(left), Fragment(right)) => self.diff_vfragment(left, right),
|
||||||
(Component(left), Component(right)) => self.diff_vcomponent(left, right),
|
(Component(left), Component(right)) => self.diff_vcomponent(left, right),
|
||||||
_ => self.replace(left_template, right_template, left_node, right_node),
|
_ => self.replace(left_template, right_template),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -196,7 +195,7 @@ impl<'b: 'static> 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) {
|
match matching_components(left, right) {
|
||||||
None => self.replace_template(left, right),
|
None => self.replace(left, right),
|
||||||
Some(components) => components
|
Some(components) => components
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.for_each(|(l, r)| self.diff_vcomponent(l, r)),
|
.for_each(|(l, r)| self.diff_vcomponent(l, r)),
|
||||||
@@ -236,63 +235,98 @@ impl<'b: 'static> VirtualDom {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn replace_nodes_with_placeholder(&mut self, l: &'b [VNode<'b>], r: &'b Cell<ElementId>) {
|
fn replace_nodes_with_placeholder(&mut self, l: &'b [VNode<'b>], r: &'b Cell<ElementId>) {
|
||||||
//
|
// Remove the old nodes, except for onea
|
||||||
// Remove the old nodes, except for one
|
|
||||||
self.remove_nodes(&l[1..]);
|
self.remove_nodes(&l[1..]);
|
||||||
let first = self.find_first_element(&l[0]);
|
let first = self.replace_inner(&l[0]);
|
||||||
self.remove_all_but_first_node(&l[0]);
|
|
||||||
|
|
||||||
let placeholder = self.next_element(&l[0], &[]);
|
let placeholder = self.next_element(&l[0], &[]);
|
||||||
r.set(placeholder);
|
r.set(placeholder);
|
||||||
|
|
||||||
self.mutations
|
self.mutations
|
||||||
.push(Mutation::CreatePlaceholder { id: placeholder });
|
.push(Mutation::CreatePlaceholder { id: placeholder });
|
||||||
self.mutations
|
self.mutations
|
||||||
.push(Mutation::ReplaceWith { id: first, m: 1 })
|
.push(Mutation::ReplaceWith { id: first, m: 1 });
|
||||||
|
|
||||||
|
self.reclaim(first);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove all the top-level nodes, returning the
|
// Remove all the top-level nodes, returning the firstmost root ElementId
|
||||||
fn remove_all_but_first_node(&mut self, node: &'b VNode<'b>) {
|
fn replace_inner(&mut self, node: &'b VNode<'b>) -> ElementId {
|
||||||
match &node.template.roots[0] {
|
let id = match &node.template.roots[0] {
|
||||||
TemplateNode::Text(_) | TemplateNode::Element { .. } => {}
|
TemplateNode::Text(_) | TemplateNode::Element { .. } => node.root_ids[0].get(),
|
||||||
TemplateNode::DynamicText(id) | TemplateNode::Dynamic(id) => {
|
TemplateNode::DynamicText(id) | TemplateNode::Dynamic(id) => {
|
||||||
match &node.dynamic_nodes[*id] {
|
match &node.dynamic_nodes[*id] {
|
||||||
Text(_) => {}
|
Text(t) => t.id.get(),
|
||||||
Fragment(VFragment::Empty(_)) => {}
|
Fragment(VFragment::Empty(e)) => e.get(),
|
||||||
Fragment(VFragment::NonEmpty(nodes)) => {
|
Fragment(VFragment::NonEmpty(nodes)) => {
|
||||||
self.remove_all_but_first_node(&nodes[0]);
|
let id = self.replace_inner(&nodes[0]);
|
||||||
self.remove_nodes(&nodes[1..]);
|
self.remove_nodes(&nodes[1..]);
|
||||||
|
id
|
||||||
}
|
}
|
||||||
Component(comp) => {
|
Component(comp) => {
|
||||||
let scope = comp.scope.get().unwrap();
|
let scope = comp.scope.get().unwrap();
|
||||||
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.remove_all_but_first_node(t),
|
RenderReturn::Sync(Ok(t)) => self.replace_inner(t),
|
||||||
_ => todo!("cannot handle nonstandard nodes"),
|
_ => todo!("cannot handle nonstandard nodes"),
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
// Just remove the rest
|
// Just remove the rest from the dom
|
||||||
for (idx, _) in node.template.roots.iter().enumerate().skip(1) {
|
for (idx, _) in node.template.roots.iter().enumerate().skip(1) {
|
||||||
self.remove_root_node(node, idx);
|
self.remove_root_node(node, idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Garabge collect all of the nodes since this gets used in replace
|
||||||
|
self.clean_up_node(node);
|
||||||
|
|
||||||
|
id
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Clean up the node, not generating mutations
|
||||||
|
///
|
||||||
|
/// Simply walks through the dynamic nodes
|
||||||
|
fn clean_up_node(&mut self, node: &'b VNode<'b>) {
|
||||||
|
for node in node.dynamic_nodes {
|
||||||
|
match node {
|
||||||
|
Component(comp) => {
|
||||||
|
let scope = comp.scope.get().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"),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Text(t) => self.reclaim(t.id.get()),
|
||||||
|
Fragment(VFragment::Empty(t)) => self.reclaim(t.get()),
|
||||||
|
Fragment(VFragment::NonEmpty(nodes)) => {
|
||||||
|
nodes.into_iter().for_each(|node| self.clean_up_node(node))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_root_node(&mut self, node: &'b VNode<'b>, idx: usize) {
|
fn remove_root_node(&mut self, node: &'b VNode<'b>, idx: usize) {
|
||||||
let root = node.template.roots[idx];
|
let root = node.template.roots[idx];
|
||||||
match root {
|
match root {
|
||||||
TemplateNode::Element { .. } | TemplateNode::Text(_) => {
|
TemplateNode::Element { .. } | TemplateNode::Text(_) => {
|
||||||
self.mutations.push(Mutation::Remove {
|
let id = node.root_ids[idx].get();
|
||||||
id: node.root_ids[idx].get(),
|
self.mutations.push(Mutation::Remove { id });
|
||||||
})
|
self.reclaim(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
TemplateNode::DynamicText(id) | TemplateNode::Dynamic(id) => {
|
TemplateNode::DynamicText(id) | TemplateNode::Dynamic(id) => {
|
||||||
match &node.dynamic_nodes[id] {
|
match &node.dynamic_nodes[id] {
|
||||||
Text(i) => self.mutations.push(Mutation::Remove { id: i.id.get() }),
|
Text(i) => {
|
||||||
|
let id = i.id.get();
|
||||||
|
self.mutations.push(Mutation::Remove { id });
|
||||||
|
self.reclaim(id);
|
||||||
|
}
|
||||||
Fragment(VFragment::Empty(e)) => {
|
Fragment(VFragment::Empty(e)) => {
|
||||||
self.mutations.push(Mutation::Remove { id: e.get() })
|
let id = e.get();
|
||||||
|
self.mutations.push(Mutation::Remove { id });
|
||||||
|
self.reclaim(id);
|
||||||
}
|
}
|
||||||
Fragment(VFragment::NonEmpty(nodes)) => self.remove_nodes(nodes),
|
Fragment(VFragment::NonEmpty(nodes)) => self.remove_nodes(nodes),
|
||||||
Component(comp) => {
|
Component(comp) => {
|
||||||
@@ -789,26 +823,15 @@ impl<'b: 'static> VirtualDom {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn replace_template(&mut self, left: &'b VNode<'b>, right: &'b VNode<'b>) {
|
fn replace(&mut self, left: &'b VNode<'b>, right: &'b VNode<'b>) {
|
||||||
todo!("replacing should work!")
|
let first = self.find_first_element(left);
|
||||||
}
|
let id = self.replace_inner(left);
|
||||||
|
let created = self.create(right);
|
||||||
fn replace(
|
self.mutations.push(Mutation::ReplaceWith {
|
||||||
&mut self,
|
id: first,
|
||||||
left_template: &'b VNode<'b>,
|
m: created,
|
||||||
right_template: &'b VNode<'b>,
|
});
|
||||||
left: &'b DynamicNode<'b>,
|
self.reclaim(id);
|
||||||
right: &'b DynamicNode<'b>,
|
|
||||||
) {
|
|
||||||
// Remove all but the first root
|
|
||||||
for root in &left_template.template.roots[1..] {
|
|
||||||
match root {
|
|
||||||
TemplateNode::Element { .. } => todo!(),
|
|
||||||
TemplateNode::Text(_) => todo!(),
|
|
||||||
TemplateNode::Dynamic(_) => todo!(),
|
|
||||||
TemplateNode::DynamicText(_) => todo!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
use crate::{nodes::VNode, scopes::ScopeId, virtual_dom::VirtualDom, DynamicNode, Mutations};
|
use crate::{
|
||||||
|
nodes::VNode, scopes::ScopeId, virtual_dom::VirtualDom, DynamicNode, ElementId, Mutations,
|
||||||
|
};
|
||||||
|
|
||||||
impl<'b> VirtualDom {
|
impl<'b> VirtualDom {
|
||||||
pub fn drop_scope(&mut self, id: ScopeId) {
|
pub fn drop_scope(&mut self, id: ScopeId) {
|
||||||
@@ -11,6 +13,11 @@ impl<'b> VirtualDom {
|
|||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn reclaim(&mut self, el: ElementId) {
|
||||||
|
assert_ne!(el, ElementId(0));
|
||||||
|
self.elements.remove(el.0);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn drop_template(
|
pub fn drop_template(
|
||||||
&mut self,
|
&mut self,
|
||||||
mutations: &mut Mutations,
|
mutations: &mut Mutations,
|
||||||
|
|||||||
@@ -78,19 +78,22 @@ impl VirtualDom {
|
|||||||
let template: &VNode = unsafe { std::mem::transmute(template) };
|
let template: &VNode = unsafe { std::mem::transmute(template) };
|
||||||
let mutations: &mut Mutations = unsafe { std::mem::transmute(mutations) };
|
let mutations: &mut Mutations = unsafe { std::mem::transmute(mutations) };
|
||||||
|
|
||||||
todo!();
|
std::mem::swap(&mut self.mutations, mutations);
|
||||||
// let place_holder_id = scope.placeholder.get().unwrap();
|
|
||||||
// self.scope_stack.push(scope_id);
|
|
||||||
// let created = self.create(mutations, template);
|
|
||||||
// self.scope_stack.pop();
|
|
||||||
// mutations.push(Mutation::ReplaceWith {
|
|
||||||
// id: place_holder_id,
|
|
||||||
// m: created,
|
|
||||||
// });
|
|
||||||
|
|
||||||
// for leaf in self.collected_leaves.drain(..) {
|
let place_holder_id = scope.placeholder.get().unwrap();
|
||||||
// fiber.waiting_on.borrow_mut().insert(leaf);
|
self.scope_stack.push(scope_id);
|
||||||
// }
|
let created = self.create(template);
|
||||||
|
self.scope_stack.pop();
|
||||||
|
mutations.push(Mutation::ReplaceWith {
|
||||||
|
id: place_holder_id,
|
||||||
|
m: created,
|
||||||
|
});
|
||||||
|
|
||||||
|
for leaf in self.collected_leaves.drain(..) {
|
||||||
|
fiber.waiting_on.borrow_mut().insert(leaf);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::mem::swap(&mut self.mutations, mutations);
|
||||||
|
|
||||||
if fiber.waiting_on.borrow().is_empty() {
|
if fiber.waiting_on.borrow().is_empty() {
|
||||||
println!("fiber is finished!");
|
println!("fiber is finished!");
|
||||||
|
|||||||
@@ -1,69 +1,30 @@
|
|||||||
//! we should properly bubble up errors from components
|
//! we should properly bubble up errors from components
|
||||||
|
|
||||||
use std::{error::Error as StdError, marker::PhantomData, string::ParseError};
|
|
||||||
|
|
||||||
use anyhow::{anyhow, bail};
|
|
||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
// todo: add these to dioxus
|
|
||||||
pub trait Reject<E: Clone>: Sized {
|
|
||||||
fn reject_err(self, t: impl FnOnce(E) -> anyhow::Error) -> Result<Self, anyhow::Error> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
fn reject_because(self, t: impl Into<String>) -> Result<Self, anyhow::Error> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn reject(self) -> Result<Self, anyhow::Error> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T, E: Clone> Reject<E> for &Result<T, E> {
|
|
||||||
fn reject_err(self, t: impl FnOnce(E) -> anyhow::Error) -> Result<Self, anyhow::Error> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Call "clone" on the underlying error so it can be propogated out
|
|
||||||
pub trait CloneErr<T, E: ToOwned> {
|
|
||||||
fn clone_err(&self) -> Result<&T, E::Owned>
|
|
||||||
where
|
|
||||||
Self: Sized;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<E: ToOwned, T> CloneErr<T, E> for Result<T, E> {
|
|
||||||
fn clone_err(&self) -> Result<&T, E::Owned>
|
|
||||||
where
|
|
||||||
Self: Sized,
|
|
||||||
{
|
|
||||||
match self {
|
|
||||||
Ok(s) => Ok(s),
|
|
||||||
Err(e) => Err(e.to_owned()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn app(cx: Scope) -> Element {
|
fn app(cx: Scope) -> Element {
|
||||||
// propgates error upwards, does not give a reason, lets Dioxus figure it out
|
let raw = match cx.generation() % 2 {
|
||||||
let value = cx.use_hook(|| "123123123.123".parse::<f32>()).reject()?;
|
0 => "123.123",
|
||||||
|
1 => "123.123.123",
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
// propgates error upwards, gives a reason
|
let value = raw.parse::<f32>()?;
|
||||||
let value = cx
|
|
||||||
.use_hook(|| "123123123.123".parse::<f32>())
|
|
||||||
.reject_because("Parsing float failed")?;
|
|
||||||
|
|
||||||
let value = cx.use_hook(|| "123123123.123".parse::<f32>()).clone_err()?;
|
cx.render(rsx! {
|
||||||
|
div { "hello {value}" }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
let value = cx
|
#[test]
|
||||||
.use_hook(|| "123123123.123".parse::<f32>())
|
fn it_goes() {
|
||||||
.as_ref()
|
let mut dom = VirtualDom::new(app);
|
||||||
.map_err(Clone::clone)?;
|
|
||||||
|
|
||||||
let value = cx
|
let edits = dom.rebuild().santize();
|
||||||
.use_hook(|| "123123123.123".parse::<f32>())
|
|
||||||
.as_ref()
|
|
||||||
.map_err(|_| anyhow!("Parsing float failed"))?;
|
|
||||||
|
|
||||||
todo!()
|
dbg!(edits);
|
||||||
|
|
||||||
|
dom.mark_dirty_scope(ScopeId(0));
|
||||||
|
|
||||||
|
dom.render_immediate();
|
||||||
}
|
}
|
||||||
@@ -16,7 +16,7 @@ fn empty_fragment_creates_nothing() {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
edits.edits,
|
edits.edits,
|
||||||
[
|
[
|
||||||
CreatePlaceholder { id: ElementId(2) },
|
CreatePlaceholder { id: ElementId(1) },
|
||||||
AppendChildren { m: 1 }
|
AppendChildren { m: 1 }
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ fn list_renders() {
|
|||||||
CreateElement { name: "div" },
|
CreateElement { name: "div" },
|
||||||
// todo: since this is the only child, we should just use
|
// todo: since this is the only child, we should just use
|
||||||
// append when modify the values (IE no need for a placeholder)
|
// append when modify the values (IE no need for a placeholder)
|
||||||
CreatePlaceholder { id: ElementId(0) },
|
CreateStaticPlaceholder,
|
||||||
AppendChildren { m: 1 },
|
AppendChildren { m: 1 },
|
||||||
SaveTemplate { name: "template", m: 1 },
|
SaveTemplate { name: "template", m: 1 },
|
||||||
// Create the inner template div
|
// Create the inner template div
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
use dioxus::core::{ElementId, Mutation::*};
|
||||||
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
|
/// As we clean up old templates, the ID for the node should cycle
|
||||||
|
#[test]
|
||||||
|
fn cycling_elements() {
|
||||||
|
let mut dom = VirtualDom::new(|cx| {
|
||||||
|
cx.render(match cx.generation() % 2 {
|
||||||
|
0 => rsx! { div { "wasd" } },
|
||||||
|
1 => rsx! { div { "abcd" } },
|
||||||
|
_ => unreachable!(),
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
let edits = dom.rebuild().santize();
|
||||||
|
assert_eq!(
|
||||||
|
edits.edits,
|
||||||
|
[
|
||||||
|
LoadTemplate { name: "template", index: 0, id: ElementId(1,) },
|
||||||
|
AppendChildren { m: 1 },
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
dom.mark_dirty_scope(ScopeId(0));
|
||||||
|
assert_eq!(
|
||||||
|
dom.render_immediate().santize().edits,
|
||||||
|
[
|
||||||
|
LoadTemplate { name: "template", index: 0, id: ElementId(2,) },
|
||||||
|
ReplaceWith { id: ElementId(1,), m: 1 },
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
// notice that the IDs cycle back to ElementId(1), preserving a minimal memory footprint
|
||||||
|
dom.mark_dirty_scope(ScopeId(0));
|
||||||
|
assert_eq!(
|
||||||
|
dom.render_immediate().santize().edits,
|
||||||
|
[
|
||||||
|
LoadTemplate { name: "template", index: 0, id: ElementId(1,) },
|
||||||
|
ReplaceWith { id: ElementId(2,), m: 1 },
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
dom.mark_dirty_scope(ScopeId(0));
|
||||||
|
assert_eq!(
|
||||||
|
dom.render_immediate().santize().edits,
|
||||||
|
[
|
||||||
|
LoadTemplate { name: "template", index: 0, id: ElementId(2,) },
|
||||||
|
ReplaceWith { id: ElementId(1,), m: 1 },
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -47,14 +47,38 @@ fn element_swap() {
|
|||||||
vdom.rebuild();
|
vdom.rebuild();
|
||||||
|
|
||||||
vdom.mark_dirty_scope(ScopeId(0));
|
vdom.mark_dirty_scope(ScopeId(0));
|
||||||
dbg!(vdom.render_immediate());
|
assert_eq!(
|
||||||
|
vdom.render_immediate().santize().edits,
|
||||||
|
[
|
||||||
|
LoadTemplate { name: "template", index: 0, id: ElementId(2,) },
|
||||||
|
ReplaceWith { id: ElementId(1,), m: 1 },
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
vdom.mark_dirty_scope(ScopeId(0));
|
vdom.mark_dirty_scope(ScopeId(0));
|
||||||
dbg!(vdom.render_immediate());
|
assert_eq!(
|
||||||
|
vdom.render_immediate().santize().edits,
|
||||||
|
[
|
||||||
|
LoadTemplate { name: "template", index: 0, id: ElementId(3,) },
|
||||||
|
ReplaceWith { id: ElementId(2,), m: 1 },
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
vdom.mark_dirty_scope(ScopeId(0));
|
vdom.mark_dirty_scope(ScopeId(0));
|
||||||
dbg!(vdom.render_immediate());
|
assert_eq!(
|
||||||
|
vdom.render_immediate().santize().edits,
|
||||||
|
[
|
||||||
|
LoadTemplate { name: "template", index: 0, id: ElementId(4,) },
|
||||||
|
ReplaceWith { id: ElementId(3,), m: 1 },
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
vdom.mark_dirty_scope(ScopeId(0));
|
vdom.mark_dirty_scope(ScopeId(0));
|
||||||
dbg!(vdom.render_immediate());
|
assert_eq!(
|
||||||
|
vdom.render_immediate().santize().edits,
|
||||||
|
[
|
||||||
|
LoadTemplate { name: "template", index: 0, id: ElementId(5,) },
|
||||||
|
ReplaceWith { id: ElementId(4,), m: 1 },
|
||||||
|
]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
@@ -16,7 +16,7 @@ async fn it_works() {
|
|||||||
[
|
[
|
||||||
CreateElement { name: "div" },
|
CreateElement { name: "div" },
|
||||||
CreateStaticText { value: "Waiting for child..." },
|
CreateStaticText { value: "Waiting for child..." },
|
||||||
CreatePlaceholder { id: ElementId(0) },
|
CreateStaticPlaceholder,
|
||||||
AppendChildren { m: 2 },
|
AppendChildren { m: 2 },
|
||||||
SaveTemplate { name: "template", m: 1 }
|
SaveTemplate { name: "template", m: 1 }
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -255,10 +255,9 @@ impl<'a> DynamicContext<'a> {
|
|||||||
self.dynamic_nodes.push(root);
|
self.dynamic_nodes.push(root);
|
||||||
self.node_paths.push(self.current_path.clone());
|
self.node_paths.push(self.current_path.clone());
|
||||||
|
|
||||||
if let BodyNode::Text(_) = root {
|
match root {
|
||||||
quote! { ::dioxus::core::TemplateNode::DynamicText(#ct) }
|
BodyNode::Text(_) => quote! { ::dioxus::core::TemplateNode::DynamicText(#ct) },
|
||||||
} else {
|
_ => quote! { ::dioxus::core::TemplateNode::Dynamic(#ct) },
|
||||||
quote! { ::dioxus::core::TemplateNode::Dynamic(#ct) }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user