Expand description
A runtime-agnostic oneshot broadcast channel for Rust.
Copyright (c) 2025 Stephen Waits steve@waits.net
This crate provides a simple way to broadcast a value once to multiple listeners.
It’s built on Arc<OnceLock> and event-listener for efficiency and runtime agnosticism.
§Features
- Simple API - Create, announce, listen
- Fast - Built on
Arc<OnceLock>andevent-listener - Runtime-agnostic - Works with tokio, async-std, smol, or any executor
- Type-safe - Can only announce once, listeners are cloneable
- Lightweight - Minimal dependencies
- Thread-safe - All types are Send + Sync when T: Send + Sync
- Cancel-safe - Async operations can be safely cancelled
§Feature Flags
default- Includes std featurestd- Enables std library support (required for blocking operations:listen_blocking(),listen_timeout_blocking())tracing- Enables tracing integration for debugging
§Quick Start
use announcement::Announcement;
#[tokio::main]
async fn main() {
// Create announcement channel
let (announcer, announcement) = Announcement::new();
// Create multiple listeners
let listener1 = announcement.listener();
let listener2 = announcement.listener();
// Spawn tasks
tokio::spawn(async move {
let value = listener1.listen().await;
println!("Listener 1: {:?}", value);
});
tokio::spawn(async move {
let value = listener2.listen().await;
println!("Listener 2: {:?}", value);
});
// Announce to all listeners
announcer.announce(42).unwrap();
}§Use Cases
- Shutdown signals - Notify all tasks to shut down
- Configuration broadcast - Share initialized config to all workers
- Lazy initialization - Signal when a resource is ready
- Event fanout - Broadcast a one-time event to multiple subscribers
§Comparison to Alternatives
Unlike tokio::sync::broadcast, announcement is:
- Single-shot (announce once)
- Runtime-agnostic
- Simpler API for one-time broadcasts
§Performance
- Announcement creation: ~200ns
- Listener creation: ~20ns
- Announce operation: ~10-40ns
- Listen (already announced): ~5-10ns
For N listeners with Arc<T>:
- Memory: O(1) - single allocation of T
- Time: O(N) arc clones (~10ns each)
§Thread Safety & Memory Model
All types (Announcement, Announcer, Listener) are Send + Sync when T: Send + Sync.
§Memory Ordering Guarantees
- Announce → Listen: The announce operation has a happens-before relationship with
all listen operations. Any writes before
announce()are visible afterlisten()returns. - Closed Flag: Uses SeqCst ordering to ensure visibility of the closed state across all threads, including on weakly-ordered architectures (ARM, RISC-V, PowerPC).
- Value Storage:
OnceLockprovides its own synchronization guarantees.
§TOCTOU Protection
All async listen operations use a double-check pattern to prevent Time-Of-Check-Time-Of-Use races between checking for a value and waiting for notification.
§Cancel Safety
The listen() method is cancel-safe: dropping the future will not lose the announced value.
You can safely use it with select!, timeout, or any operation that might cancel the future.
The value remains available for subsequent listen() or try_listen() calls.
Structs§
- Announcement
- The main announcement channel type that creates listeners.
- Announcer
- The sending end of the announcement channel.
- Listener
- A listener that waits for an announced value.
Enums§
- Announce
Error - Error returned when attempting to announce a value.
- Listen
Error - Error returned when listening for a value.