93 lines
3.8 KiB
Markdown
93 lines
3.8 KiB
Markdown
# Модуль реактивности: `src/interpreter/reactive.rs`
|
||
|
||
Система отслеживания зависимостей между переменными и элементами VDOM.
|
||
Позволяет пересчитывать только изменившиеся элементы (Phase 3).
|
||
|
||
---
|
||
|
||
## `ElementId(u32)`
|
||
|
||
Уникальный идентификатор элемента в VDOM-дереве. Раздаётся `ReactiveTracker::alloc_id()`
|
||
во время загрузки шаблона.
|
||
|
||
```rust
|
||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||
pub struct ElementId(pub u32);
|
||
```
|
||
|
||
**Используется как:**
|
||
- Ключ в `dirty_set: HashSet<ElementId>`
|
||
- Ключ в `dependencies: HashMap<ElementId, HashSet<String>>`
|
||
- Поле в `Element::element_id` (связь VDOM → tracker)
|
||
- Источник для `iced::widget::Id` (Phase 9.2: `format!("ti:{}", id.0)`)
|
||
- Источник для scrollable_id (`el.element_id.0 as u64`)
|
||
|
||
---
|
||
|
||
## `ReactiveTracker`
|
||
|
||
Граф зависимостей: переменная → список элементов, которые её используют.
|
||
|
||
```rust
|
||
pub struct ReactiveTracker {
|
||
subscribers: HashMap<String, HashSet<ElementId>>,
|
||
dependencies: HashMap<ElementId, HashSet<String>>,
|
||
dirty_set: HashSet<ElementId>,
|
||
next_id: u32,
|
||
}
|
||
```
|
||
|
||
**Поля:**
|
||
- `subscribers` — для каждой переменной: какие ElementId от неё зависят
|
||
- `dependencies` — для каждого элемента: от каких переменных он зависит (обратная связь)
|
||
- `dirty_set` — элементы, которые нужно пересчитать в следующем фрейме
|
||
- `next_id` — счётчик для `alloc_id()`
|
||
|
||
### Методы
|
||
|
||
| Метод | Описание |
|
||
|-------|----------|
|
||
| `new()` | Пустой tracker |
|
||
| `alloc_id() -> ElementId` | Выделить новый ID, увеличить счётчик |
|
||
| `add_dependency(element, var_name)` | Зарегистрировать зависимость |
|
||
| `scan_value(element, value)` | Сканировать строку на `$var` и добавить зависимости |
|
||
| `on_variable_changed(name)` | Пометить все зависимые элементы как dirty |
|
||
| `take_dirty_set() -> HashSet<ElementId>` | Забрать dirty_set и очистить |
|
||
| `is_dirty(id) -> bool` | Проверить, помечен ли элемент |
|
||
| `reset()` | Очистить все данные |
|
||
|
||
### scan_value()
|
||
|
||
Парсит строку в поиске `$var_name` паттернов:
|
||
|
||
```rust
|
||
"Hello $name, you are $age years old"
|
||
// → add_dependency(element, "name")
|
||
// → add_dependency(element, "age")
|
||
```
|
||
|
||
Используется во время загрузки шаблона для каждой properties строки,
|
||
содержащей `$`. В результате каждый элемент знает, от каких переменных зависит.
|
||
|
||
### Цикл обновления
|
||
|
||
```
|
||
Событие → update() → on_variable_changed("var")
|
||
→ dirty_set = {element_A, element_B, ...}
|
||
→ take_dirty_set() → evaluate_vdom_incr(roots, &dirty_set)
|
||
→ для элементов в dirty_set: пересчитать
|
||
→ для остальных: вернуть как есть
|
||
```
|
||
|
||
---
|
||
|
||
## Тесты
|
||
|
||
| Тест | Что проверяет |
|
||
|------|--------------|
|
||
| `test_basic_dependency_tracking` | Два элемента, две переменные, правильность dirty_set |
|
||
| `test_scan_value` | Парсинг `$var` из строки |
|
||
| `test_scan_no_vars` | Строка без `$` не создаёт зависимостей |
|
||
| `test_take_dirty_set` | `take_dirty_set()` очищает внутренний set |
|
||
| `test_reset` | `reset()` очищает всё |
|