#thread-safe #lock-free #listener #callback #observer

listener-holder

A thread-safe single-listener holder with lock-free reads for Rust

2 releases

0.1.1 Mar 7, 2026
0.1.0 Mar 7, 2026

#577 in Concurrency

MIT/Apache

11KB
104 lines

listener-holder

A thread-safe, lock-free read single-listener holder for Rust.

Use it when you have one optional callback/listener that may be set or cleared at runtime, and you want to notify it from any thread without repeating RwLock<Option<...>> boilerplate.

Requirements

  • The listener type L must implement Send + Sync. The holder is then safe to share across threads (e.g. via Arc<ListenerHolder<L>>).

Features

  • Thread-safe: ListenerHolder<L> is Send + Sync when L: Send + Sync. Safe to share via Arc across threads.
  • Lock-free reads: Uses arc-swap internally; getting and notifying the listener do not take a lock. See docs/CONCURRENCY.md for comparison with RwLock<Option<Arc<L>>>.
  • Single listener: Holds at most one listener; setting a new one replaces the previous.
  • Simple API: set (pass None to clear), with_listener, get.

Usage

[dependencies]
listener-holder = "0.1.1"
use listener_holder::ListenerHolder;
use std::sync::Arc;

// Your listener type must be Send + Sync
struct MyListener;
impl MyListener {
    fn on_event(&self, msg: &str) {
        println!("event: {}", msg);
    }
}

let holder = ListenerHolder::new();

// Set listener
holder.set(Some(Arc::new(MyListener)));

// Notify (only if listener is set)
holder.with_listener(|l| l.on_event("hello"));

// Clear (pass None)
holder.set(None);
holder.with_listener(|l| l.on_event("ignored")); // no-op

// Get a clone of the current listener (e.g. to call from async code outside the lock)
if let Some(listener) = holder.get() {
    listener.on_event("from get()");
}

When to use

  • SDK or engine that exposes a single optional listener (e.g. connection listener, migration progress listener).
  • You were about to write RwLock<Option<Arc<dyn Listener>>> and want a ready-made type instead.

Panics

  • with_listener does not panic by itself. If the closure you pass panics, the holder is left unchanged and other threads can continue to use it.
  • No other method panics under normal use.

License

MIT OR Apache-2.0

Dependencies

~190KB