Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

TreeModel

TreeModel — concrete reactive tree with shared, cloneable handles.

TreeModel<T> owns a hierarchy of T items in a flat SlotMap arena with parent-child links. Every structural mutation (insert_root, insert_child, remove, move_node, update) emits a TreeChange to all registered observers before returning. Node identity is a stable, versioned NodeId (a SlotMap key) that is never reused after removal.

Cloning produces a second handle to the same data — all handles see the same hierarchy and receive the same change notifications. Register observers via observe_changes; the returned ObserverHandle is RAII — dropping it unregisters the callback.

For per-view expand/collapse state wrap the model in a TreeSlice. For sort/filter projections use SortFilterTreeModel.

Example

#![allow(unused)]
fn main() {
use teksilo_data::{TreeModel, TreeChange};
let tree = TreeModel::new();
let root = tree.insert_root(0, "root");
let child = tree.insert_child(root, 0, "child");

assert_eq!(tree.root_count(), 1);
assert_eq!(tree.child_count(root), 1);
assert_eq!(tree.parent(child), Some(root));

let clone = tree.clone();
clone.insert_root(1, "root2");
assert_eq!(tree.root_count(), 2); // both handles share the same data
}

Builder methods at a glance

root_count, root, child_count, child, parent, depth, has_children, children, with_item, find_by, insert_root, insert_child, remove, move_node, move_to_root, update, observe_changes, debug_named

API reference

📖 Full rustdoc API for this module

pub struct TreeModel

A concrete reactive tree that stores a hierarchy of T items in a flat arena.

TreeModel<T> is Clone — cloning produces a second handle to the same underlying data. All handles see the same hierarchy and receive the same TreeChange notifications from observe_changes. Nodes are identified by opaque NodeId handles that are stable and non-reusable across mutations (versioned SlotMap keys).

#![allow(unused)]
fn main() {
pub struct TreeModel<T: 'static> { /* fields */ }
}

Methods

pub fn new() -> Self

Create an empty tree model with no roots and no observers.

pub fn root_count(&self) -> usize

Number of root-level nodes.

pub fn root(&self, index: usize) -> NodeId

Get the NodeId of a root-level node by index.

Panics

Panics if index >= root_count().

pub fn child_count(&self, parent: NodeId) -> usize

Number of children of the given node.

pub fn child(&self, parent: NodeId, index: usize) -> NodeId

Get the NodeId of a child by parent and index.

Panics

Panics if the parent or index is invalid.

pub fn parent(&self, node: NodeId) -> Option<NodeId>

Get the parent of a node, or None if it is a root.

pub fn depth(&self, node: NodeId) -> usize

Compute the depth of a node (0 for roots).

pub fn has_children(&self, node: NodeId) -> bool

Whether the given node has any children.

pub fn children(&self, node: NodeId) -> Vec<NodeId>

Get the children of a node as a vector of NodeId.

pub fn with_item<R>(&self, node: NodeId, f: impl FnOnce(&T) -> R) -> Option<R>

Access a node's data via a callback. Returns None if the node doesn't exist.

pub fn find_by(&self, predicate: impl Fn(&T) -> bool) -> Option<NodeId>

Find the first node matching a predicate (depth-first from roots).

pub fn insert_root(&self, index: usize, item: T) -> NodeId

Insert a new root-level node at the given index.

Panics

Panics if index > root_count().

pub fn insert_child(&self, parent: NodeId, index: usize, item: T) -> NodeId

Insert a new child node under the given parent at the given index.

Panics

Panics if the parent is invalid or index > child_count(parent).

pub fn remove(&self, node: NodeId)

Remove a node and its entire subtree.

Panics

Panics if the node is invalid.

pub fn move_node(&self, node: NodeId, new_parent: NodeId, new_index: usize)

Move a node (and its subtree) to a new parent at the given index.

Panics

Panics if any of the nodes are invalid, or if the target is a descendant of the source (would create a cycle).

pub fn move_to_root(&self, node: NodeId, new_index: usize)

Move a node to the root level at the given index.

pub fn update(&self, node: NodeId, item: T)

Update a node's data in place.

Panics

Panics if the node is invalid.

pub fn observe_changes(&self, f: impl Fn(&TreeChange) + 'static) -> ObserverHandle

Register an observer for tree change notifications. Returns an ObserverHandle — dropping it removes the callback.

pub fn debug_named(self, _name: impl Into<String>) -> Self

Register this tree with the debug inspector under name. In release builds (!cfg(debug_assertions)) this is a no-op pass-through so call sites stay free of #[cfg] lines.

Idempotent on repeated calls — the latest registration wins. The registration drops automatically when the last TreeModel handle is freed (the adapter the registry holds is Weak).