ftui_runtime/reactive/mod.rs
1#![forbid(unsafe_code)]
2
3//! Reactive data bindings for FrankenTUI.
4//!
5//! This module provides change-tracking primitives for reactive UI updates:
6//!
7//! - [`Observable`]: A shared, version-tracked value wrapper with change
8//! notification via subscriber callbacks.
9//! - [`Subscription`]: RAII guard that automatically unsubscribes on drop.
10//! - [`Computed`]: A lazily-evaluated, memoized value derived from one or
11//! more `Observable` dependencies.
12//! - [`BatchScope`]: RAII guard that defers all `Observable` notifications
13//! until the scope exits, preventing intermediate renders.
14//!
15//! # Architecture
16//!
17//! `Observable<T>` uses `Rc<RefCell<..>>` for single-threaded shared ownership.
18//! Subscribers are stored as `Weak` function pointers and cleaned up lazily
19//! during notification.
20//!
21//! `Computed<T>` subscribes to its sources via `Observable::subscribe()`,
22//! marking itself dirty on change. Recomputation is deferred until `get()`.
23//!
24//! `BatchScope` uses a thread-local context to defer notifications. Nested
25//! scopes are supported; only the outermost scope triggers flush.
26//!
27//! # Invariants
28//!
29//! 1. Version increments exactly once per mutation that changes the value.
30//! 2. Subscribers are notified in registration order.
31//! 3. Setting a value equal to the current value is a no-op (no version bump,
32//! no notifications).
33//! 4. Dropping a [`Subscription`] removes the callback before the next
34//! notification cycle.
35//! 5. `Computed::get()` never returns a stale value.
36//! 6. Within a `BatchScope`, values are updated immediately but notifications
37//! are deferred until the outermost scope exits.
38
39pub mod batch;
40pub mod binding;
41pub mod computed;
42pub mod observable;
43
44pub use batch::BatchScope;
45pub use binding::{
46 Binding, BindingScope, TwoWayBinding, bind_mapped, bind_mapped2, bind_observable,
47};
48pub use computed::Computed;
49pub use observable::{Observable, Subscription};