Signaled
A lightweight reactive programming library for Rust, providing a signal-slot mechanism. Signaled<T> holds a value and emits signals to registered callbacks when the value changes.
This library comes in two versions:
signaled::sync: A thread-safe implementation usingRwLockandMutex. Recommended for most applications.signaled: A single-threaded implementation usingRefCell. Ideal for contexts where thread safety is not required.
Features
- Reactive Updates: Update a value and automatically emit signals to registered callbacks.
- Priority-Based Signals: Signals are executed in descending priority order.
- Conditional Triggers: Signals can have trigger functions to control callback execution.
- One-Time Signals: Signals can be flagged as
once. Aoncesignal is automatically removed after its callback is successfully executed (i.e., when its trigger condition is met).
Thread-Safe Usage (signaled::sync)
The sync module provides a fully thread-safe implementation suitable for multi-threaded applications. It uses RwLock and Mutex for interior mutability.
Example
use ;
use signal_sync;
use ;
let signaled = new;
let calls = new;
let calls_clone = clone;
let signal = signal_sync!;
signaled.add_signal.unwrap;
// Set the value from different threads
let threads: = .map.collect;
for handle in threads
assert_eq!;
println!;
Error Handling (sync)
Methods may return SignaledError for:
PoisonedLock: Attempted to acquire a poisonedRwLockorMutex.WouldBlock: Atry_method failed to acquire a lock immediately.InvalidSignalId: Provided aSignalID that does not exist.
⚠️ Deadlock Warning
Incorrectly managing locks can lead to deadlocks. For example, holding a read lock on the Signaled value while trying to call set from the same thread will deadlock. Non-blocking try_* methods are provided as an alternative.
Single-Threaded Usage (signaled)
This is a high-performance version for single-threaded contexts. It uses RefCell for interior mutability and provides runtime borrow checking.
Example
use ;
let signaled = new;
let high_priority = signal!;
high_priority.set_priority;
let conditional = signal!;
conditional.set_trigger.unwrap;
signaled.add_signal.unwrap;
signaled.add_signal.unwrap;
signaled.set.unwrap;
signaled.set.unwrap;
High: Old: 0, New: 10
Conditional: Old: 0, New: 10
High: Old: 10, New: 3
Error Handling (Single-Threaded)
Methods may return SignaledError for:
BorrowError: Attempted to immutably borrow a value already mutably borrowed.BorrowMutError: Attempted to mutably borrow a value already borrowed.InvalidSignalId: Provided aSignalID that does not exist.
⚠️ Re-entrant Calls
Recursive or re-entrant calls (e.g., calling set from within a signal's callback) may cause a panic due to RefCell borrow errors.