Crate announcement

Crate announcement 

Source
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> and event-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 feature
  • std - 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 after listen() 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: OnceLock provides 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§

AnnounceError
Error returned when attempting to announce a value.
ListenError
Error returned when listening for a value.