1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
// SPDX-License-Identifier: MPL-2.0
// SPDX-FileCopyrightText: 2026 FernTech
//! TreeChange — change notifications and stable node identifiers for tree collections.
//!
//! [`NodeId`] is an opaque, stable handle for a node in a [`crate::TreeModel`].
//! Because `TreeModel` is backed by a slotmap, `NodeId` values survive arbitrary
//! insertions, removals, and moves — only deleting the node itself invalidates it.
//! [`TreeChange`] describes exactly what mutated in the tree so that projections
//! (`SortFilterTreeModel`, `TreeSlice`) can refresh efficiently and emit
//! fine-grained divergence hints.
//!
//! Consumers typically receive `TreeChange` values through an observer registered
//! via [`crate::TreeModel::observe_changes`], which fires synchronously (before
//! the registering call returns) after each mutation. The projections listed above
//! subscribe internally; app code rarely needs to subscribe directly.
//!
//! ```ignore
//! // TreeModel::observe_changes returns an ObserverHandle whose drop
//! // unregisters the callback — keep it alive for the observer's lifetime.
//! use teksilo_data::{TreeModel, TreeChange};
//! let tree: TreeModel<String> = TreeModel::new();
//! let _handle = tree.observe_changes(|change| {
//! println!("{change:?}");
//! });
//! tree.insert_root(0, "root".to_string());
//! // prints: NodeInserted { parent: None, index: 0, node: NodeId(...) }
//! ```
/// Opaque identifier for a node in a `TreeModel`.
///
/// `NodeId` values are stable across mutations — inserting or removing other
/// nodes does not invalidate existing `NodeId` handles (they are SlotMap keys).
;
/// Describes a mutation to a tree structure. Emitted by `TreeModel<T>` automatically.