93 lines
2.7 KiB
Markdown
93 lines
2.7 KiB
Markdown
# Reactivity Module: `src/interpreter/reactive.rs`
|
|
|
|
Dependency tracking system between variables and VDOM elements.
|
|
Allows recalculation of only changed elements (Phase 3).
|
|
|
|
---
|
|
|
|
## `ElementId(u32)`
|
|
|
|
Unique element identifier in the VDOM tree. Assigned by `ReactiveTracker::alloc_id()`
|
|
during template loading.
|
|
|
|
```rust
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
|
pub struct ElementId(pub u32);
|
|
```
|
|
|
|
**Used as:**
|
|
- Key in `dirty_set: HashSet<ElementId>`
|
|
- Key in `dependencies: HashMap<ElementId, HashSet<String>>`
|
|
- Field in `Element::element_id` (VDOM → tracker link)
|
|
- Source for `iced::widget::Id` (Phase 9.2: `format!("ti:{}", id.0)`)
|
|
- Source for scrollable_id (`el.element_id.0 as u64`)
|
|
|
|
---
|
|
|
|
## `ReactiveTracker`
|
|
|
|
Dependency graph: variable → list of elements that reference it.
|
|
|
|
```rust
|
|
pub struct ReactiveTracker {
|
|
subscribers: HashMap<String, HashSet<ElementId>>,
|
|
dependencies: HashMap<ElementId, HashSet<String>>,
|
|
dirty_set: HashSet<ElementId>,
|
|
next_id: u32,
|
|
}
|
|
```
|
|
|
|
**Fields:**
|
|
- `subscribers` — for each variable: which ElementIds depend on it
|
|
- `dependencies` — for each element: which variables it depends on (reverse mapping)
|
|
- `dirty_set` — elements to recalculate in the next frame
|
|
- `next_id` — counter for `alloc_id()`
|
|
|
|
### Methods
|
|
|
|
| Method | Description |
|
|
|--------|-------------|
|
|
| `new()` | Empty tracker |
|
|
| `alloc_id() -> ElementId` | Allocate a new ID, increment counter |
|
|
| `add_dependency(element, var_name)` | Register a dependency |
|
|
| `scan_value(element, value)` | Scan a string for `$var` and add dependencies |
|
|
| `on_variable_changed(name)` | Mark all dependent elements as dirty |
|
|
| `take_dirty_set() -> HashSet<ElementId>` | Take dirty_set and clear it |
|
|
| `is_dirty(id) -> bool` | Check if an element is marked dirty |
|
|
| `reset()` | Clear all data |
|
|
|
|
### scan_value()
|
|
|
|
Parses a string for `$var_name` patterns:
|
|
|
|
```rust
|
|
"Hello $name, you are $age years old"
|
|
// → add_dependency(element, "name")
|
|
// → add_dependency(element, "age")
|
|
```
|
|
|
|
Used during template loading for each properties string containing `$`.
|
|
As a result, each element knows which variables it depends on.
|
|
|
|
### Update cycle
|
|
|
|
```
|
|
Event → update() → on_variable_changed("var")
|
|
→ dirty_set = {element_A, element_B, ...}
|
|
→ take_dirty_set() → evaluate_vdom_incr(roots, &dirty_set)
|
|
→ for dirty_set elements: recalculate
|
|
→ for others: return as-is
|
|
```
|
|
|
|
---
|
|
|
|
## Tests
|
|
|
|
| Test | What it checks |
|
|
|------|---------------|
|
|
| `test_basic_dependency_tracking` | Two elements, two variables, correct dirty_set |
|
|
| `test_scan_value` | Parse `$var` from a string |
|
|
| `test_scan_no_vars` | String without `$` creates no dependencies |
|
|
| `test_take_dirty_set` | `take_dirty_set()` clears the internal set |
|
|
| `test_reset` | `reset()` clears everything |
|