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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
//! Leptos-style fine-grained reactivity.
//!
//! Design: see `docs/reactivity-design.md`.
//!
//! Quick map:
//!
//! - [`runtime`] — internal data structures: [`ReactiveRuntime`],
//! [`runtime::Scope`], [`ReactiveNode`], [`NodeData`].
//! - [`owner`] — public owner API: the [`Owner`] handle and its
//! methods ([`Owner::new`], [`Owner::with`], [`Owner::dispose`],
//! [`Owner::pause`], [`Owner::resume`], [`Owner::is_paused`])
//! plus the free function [`on_cleanup`].
//! - [`signal`] — [`signal`] / [`RwSignal`] / [`ReadSignal`] /
//! [`WriteSignal`].
//! - [`effect`] — [`effect`] + dependency tracking.
//! - [`computed`] — [`computed`] (returns [`ReadSignal<T>`]).
//! - [`scheduler`] — batching / flush.
//!
//! All operations are single-threaded — reactive UI runs on the Lynx
//! TASM thread. The runtime lives in a `thread_local!`. Operations
//! that need a runtime borrow go through [`with_runtime`], which gives
//! a `&mut ReactiveRuntime` for the duration of the closure.
//!
//! ## Why a single thread-local
//!
//! Lynx renders UI on its TASM thread; Whisker's bridge schedules all
//! reactive work onto that thread (see
//! `whisker-driver-sys/bridge/src/whisker_bridge_common.cc`). A single
//! thread-local instance keeps the implementation borrow-checker-clean
//! (no `Arc`, no locks) while matching how the runtime actually
//! executes.
pub use ;
pub use __reset_pending_mount_for_tests;
pub use ;
pub use computed;
pub use ;
pub use effect;
// `on_cleanup` lives at the module top-level because it acts on
// whichever owner is currently on the runtime stack — the caller
// can't name it. Everything else owner-related lives behind the
// `owner` module path (re-exported below) so users write
// `whisker::owner::Owner::new(None)` / `owner.with(...)` / etc.
pub use on_cleanup;
pub use Signal;
pub use ;
pub use ;
pub use flush;
pub use ;
pub use StoredValue;
use RefCell;
use ReactiveRuntime;
thread_local!
/// Open a mutable borrow on the thread-local runtime and run `f`.
///
/// **The borrow is held only for the duration of `f`.** User code that
/// needs to re-enter the runtime (e.g. reading a signal from inside an
/// effect closure) MUST drop this borrow first — the implementations
/// in this module take care to copy out whatever data they need
/// (Rc handles, NodeIds, …) in a short borrow before invoking user
/// closures.
///
/// Crate-internal; the public surface is the typed `signal` / `effect`
/// / `computed` / `Owner::dispose` etc. functions. Exposing the raw
/// runtime would let callers violate borrow-window invariants.
pub
/// Warn (debug only) when a reactive primitive is allocated outside
/// any owner. The fallback path creates a detached owner that's never
/// disposed, so this is mostly OK for one-offs (tests, app bootstrap)
/// but should not happen inside steady-state component code.
pub
pub
/// Run `f` with the runtime's `current_tracker` temporarily cleared,
/// then restore it.
///
/// Use this whenever a reactive primitive needs to invoke a user
/// closure that performs signal reads **but those reads must not
/// register dependencies against whatever outer effect / computed
/// happens to be running**. The canonical case is `computed`'s
/// construction-time seed run: the seed is just for cache initial
/// value, the real dependency edges are registered by the
/// scheduler-driven run that happens immediately afterwards.
///
/// The restore runs from a `Drop` guard, so a panic in `f` doesn't
/// leave the runtime in an "untracked" state. Re-entrant safe — if
/// `f` itself calls `untrack`, the nested guard restores `None`
/// (the value the outer guard already pushed), which is what the
/// outer guard would have done.
pub
/// (Test only) reset the thread-local runtime to an empty state. Used
/// between unit tests to keep the arena clean.