auralis-signal
Reactive signal primitive with version tracking and proactive waker deregistration.
Zero dependencies. #![forbid(unsafe_code)]. Single-threaded by design (!Send / !Sync).
Overview
| Type | Role |
|---|---|
Signal<T> |
Reactive value container with monotonic version tracking |
Memo<T> |
Lazy, auto-tracking computed signal |
SignalMap<T, U, F> |
Lightweight read-only projection (no subscription) |
SignalChangedFuture<T> |
Future that resolves on next mutation |
MapChangedFuture<T, U, F> |
Transforms each new value |
FilterChangedFuture<T, F> |
Yields only when a predicate matches |
batch(f) |
Run f with deferred notifications — multiple sets, one notification |
in_batch() |
Check if currently inside a batch |
memo!(a, b => expr) |
Convenience macro: auto-clones captured signals before the move closure |
Signal::version() |
Return the current monotonic version number |
Memo::is_dirty() |
Check whether a source has changed without triggering computation |
Memo::compute_count() |
Number of successful recomputations (including initial) |
Quick Start
use ;
// Signal
let count = new;
count.set;
assert_eq!;
// Memo (auto-tracking computed value)
let a = new;
let b = new;
let sum = new;
assert_eq!;
// Batch (multiple sets, one notification)
let x = new;
batch;
assert_eq!;
Key Properties
- Deferred callback model —
set()never invokes subscribers synchronously; callbacks are queued for the next executor flush - Proactive waker deregistration — dropping a
SignalChangedFutureimmediately removes its subscriber from the signal's list, preventing stale-waker accumulation - Panic-safe Memo — if the compute function panics, old source subscriptions stay intact; the memo recovers on the next successful
read() - Incremental subscription updates — during recompute, shared dependencies are kept; only removed/new signals trigger subscribe/unsubscribe
- Panic-safe batch —
catch_unwindaround each individual notification in the batch drain
License
Licensed under either of MIT or Apache 2.0 at your option.