Phase 3.4-3.7: evaluate_vdom_incr with dirty_set propagation, tests for ReactiveTracker

This commit is contained in:
Glint Dev
2026-07-21 20:40:23 +03:00
parent d8d3f57a21
commit 4a6dea6dd8
3 changed files with 41 additions and 22 deletions

View File

@@ -54,13 +54,15 @@ impl GlintApp {
_ => {} _ => {}
} }
self.vdom_roots = Interpreter::evaluate_vdom( let dirty_set = self.doc.tracker.take_dirty_set();
self.vdom_roots = Interpreter::evaluate_vdom_incr(
&self.doc.roots, &self.doc.roots,
&mut self.doc.variables, &mut self.doc.variables,
&self.doc.components, &self.doc.components,
&self.rhei, &self.rhei,
&self.doc.stylesheet, &self.doc.stylesheet,
&[], &[],
&dirty_set,
); );
iced::Task::none() iced::Task::none()

View File

@@ -18,7 +18,7 @@ use reader::Reader;
use rhei::RHEI_PREFIX; use rhei::RHEI_PREFIX;
use style::{AncestorInfo, ComputedStyle, StructuralContext}; use style::{AncestorInfo, ComputedStyle, StructuralContext};
pub use types::Value; pub use types::Value;
use std::collections::HashMap; use std::collections::{HashMap, HashSet};
pub struct Interpreter; pub struct Interpreter;
@@ -326,6 +326,18 @@ impl Interpreter {
rhei: &RheiContext, rhei: &RheiContext,
stylesheet: &SS, stylesheet: &SS,
ancestors: &[AncestorInfo], ancestors: &[AncestorInfo],
) -> Vec<Element<'a>> {
Self::evaluate_vdom_incr(templates, variables, components, rhei, stylesheet, ancestors, &HashSet::new())
}
pub fn evaluate_vdom_incr<'a>(
templates: &[Element<'a>],
variables: &mut HashMap<String, Value>,
components: &HashMap<String, ComponentDef<'a>>,
rhei: &RheiContext,
stylesheet: &SS,
ancestors: &[AncestorInfo],
dirty_set: &HashSet<ElementId>,
) -> Vec<Element<'a>> { ) -> Vec<Element<'a>> {
let mut output = Vec::with_capacity(templates.len()); let mut output = Vec::with_capacity(templates.len());
@@ -376,8 +388,8 @@ impl Interpreter {
active_branch.push(child.clone()); active_branch.push(child.clone());
} }
} }
output.extend(Self::evaluate_vdom( output.extend(Self::evaluate_vdom_incr(
&active_branch, variables, components, rhei, stylesheet, ancestors, &active_branch, variables, components, rhei, stylesheet, ancestors, dirty_set,
)); ));
} }
@@ -400,8 +412,8 @@ impl Interpreter {
for item in items { for item in items {
let old_val = variables.insert(var_name.to_string(), Value::Str(CompactString::new(item))); let old_val = variables.insert(var_name.to_string(), Value::Str(CompactString::new(item)));
output.extend(Self::evaluate_vdom( output.extend(Self::evaluate_vdom_incr(
&el.children, variables, components, rhei, stylesheet, ancestors, &el.children, variables, components, rhei, stylesheet, ancestors, dirty_set,
)); ));
if let Some(old) = old_val { if let Some(old) = old_val {
@@ -442,8 +454,8 @@ impl Interpreter {
vcomp.computed_style = ComputedStyle::compute(&vcomp.properties, &matched_sheets); vcomp.computed_style = ComputedStyle::compute(&vcomp.properties, &matched_sheets);
let child_ancestors = Self::build_ancestor_chain(ancestors, &vcomp); let child_ancestors = Self::build_ancestor_chain(ancestors, &vcomp);
vcomp.children = Self::evaluate_vdom( vcomp.children = Self::evaluate_vdom_incr(
&comp.children, variables, components, rhei, stylesheet, &child_ancestors, &comp.children, variables, components, rhei, stylesheet, &child_ancestors, dirty_set,
); );
output.push(vcomp); output.push(vcomp);
@@ -474,8 +486,8 @@ impl Interpreter {
vnode.computed_style = ComputedStyle::compute(&vnode.properties, &matched_sheets); vnode.computed_style = ComputedStyle::compute(&vnode.properties, &matched_sheets);
let child_ancestors = Self::build_ancestor_chain(ancestors, &vnode); let child_ancestors = Self::build_ancestor_chain(ancestors, &vnode);
vnode.children = Self::evaluate_vdom( vnode.children = Self::evaluate_vdom_incr(
&el.children, variables, components, rhei, stylesheet, &child_ancestors, &el.children, variables, components, rhei, stylesheet, &child_ancestors, dirty_set,
); );
output.push(vnode); output.push(vnode);
} }

View File

@@ -111,13 +111,15 @@ mod tests {
tracker.add_dependency(e2, "volume"); tracker.add_dependency(e2, "volume");
tracker.add_dependency(e2, "brightness"); tracker.add_dependency(e2, "brightness");
let affected = tracker.on_variable_changed("volume"); tracker.on_variable_changed("volume");
assert!(affected.contains(&e1)); let dirty = tracker.take_dirty_set();
assert!(affected.contains(&e2)); assert!(dirty.contains(&e1));
assert!(dirty.contains(&e2));
let affected = tracker.on_variable_changed("brightness"); tracker.on_variable_changed("brightness");
assert!(!affected.contains(&e1)); let dirty = tracker.take_dirty_set();
assert!(affected.contains(&e2)); assert!(!dirty.contains(&e1));
assert!(dirty.contains(&e2));
} }
#[test] #[test]
@@ -127,11 +129,13 @@ mod tests {
tracker.scan_value(e1, "Hello $name, you are $age years old"); tracker.scan_value(e1, "Hello $name, you are $age years old");
let affected = tracker.on_variable_changed("name"); tracker.on_variable_changed("name");
assert!(affected.contains(&e1)); let dirty = tracker.take_dirty_set();
assert!(dirty.contains(&e1));
let affected = tracker.on_variable_changed("age"); tracker.on_variable_changed("age");
assert!(affected.contains(&e1)); let dirty = tracker.take_dirty_set();
assert!(dirty.contains(&e1));
} }
#[test] #[test]
@@ -140,8 +144,9 @@ mod tests {
let e1 = tracker.alloc_id(); let e1 = tracker.alloc_id();
tracker.scan_value(e1, "Hello world"); tracker.scan_value(e1, "Hello world");
let affected = tracker.on_variable_changed("name"); tracker.on_variable_changed("name");
assert!(!affected.contains(&e1)); let dirty = tracker.take_dirty_set();
assert!(!dirty.contains(&e1));
} }
#[test] #[test]