Status
Active development. v0.5.0 adds the asynchronous side:
AsyncRegistry with concurrent + sequential dispatch, AsyncHandlerGuard,
panic isolation across .await, behind the async feature flag. The
synchronous side (v0.4.0) — SyncRegistry, priority ordering, RAII guards,
panic isolation — remains the default. See .dev/ROADMAP.md
for the path to 1.0.
Public API is not yet frozen — minor releases may break it. Pin specific versions; expect changes pre-1.0.
Highlights
SyncRegistry<E>— generic over the event type. Handlers receive&E.AsyncRegistry<E>(feature:async) — same lock-free storage, futures-returning handlers, concurrent or sequential dispatch.- Lock-free reads via
ArcSwapsnapshots. Many threads cannotifyconcurrently with no coordination. - Zero allocation on the no-panic sync notify path.
- Panic isolation — a panicking handler does not stop siblings nor
propagate to the caller. Optional
on_paniccallback for observability. Works for both sync handlers and async futures. - Priority ordering —
register_with_priority(i32, ...). Higher fires first; ties broken in registration order. - RAII guards —
register_guardreturns aHandlerGuard/AsyncHandlerGuardthat unregisters on drop. Send + Sync— share registries freely across threads.- Cross-platform — Linux, macOS, Windows.
When to use it
Use registry-io when you have:
- Multiple components that need notification when something happens (config reload, file change, transaction commit, metric event, etc.).
- Fast, in-process handlers measured in microseconds or less.
- A need to register and unregister handlers dynamically.
- Performance-critical paths where channel allocation would dominate.
Do not use registry-io when you have:
- Cross-process or cross-network delivery needs — use NATS, Redis pub/sub, or similar message brokers.
- Heavy handler workloads requiring backpressure — use
tokio::sync::broadcastor channels. - Event sourcing or durability requirements — use a real event log.
Quick start
[]
= "0.4"
use Arc;
use ;
use SyncRegistry;
let registry: = new;
let total = new;
let sink = clone;
let id = registry.register;
registry.notify;
registry.notify;
assert_eq!;
assert!;
Priority ordering
use ;
use SyncRegistry;
let registry: = new;
let order = new;
let o = clone;
let _ = registry.register_with_priority;
let o = clone;
let _ = registry.register;
let o = clone;
let _ = registry.register_with_priority;
registry.notify;
assert_eq!;
RAII guards
use Arc;
use SyncRegistry;
let registry = new;
// guard drops here -> handler is unregistered
assert!;
Panic isolation
use SyncRegistry;
let registry: = new;
registry.on_panic;
let _ = registry.register;
let _ = registry.register;
registry.notify; // returns cleanly; both effects observed
Async handlers (feature: async)
[]
= { = "0.5", = ["async"] }
= { = "1", = ["rt-multi-thread", "macros"] }
use Arc;
use ;
use r#AsyncRegistry;
async
Same lock-free read path as SyncRegistry. Panics in handler futures are
caught via an internal CatchUnwind adapter and surfaced through
on_panic, just like sync handlers.
See examples/ for runnable programs and docs/API.md
for the full reference.
Design philosophy
- Sync-first. The fast path is synchronous, runs on the calling thread, allocates nothing, and dispatches in nanoseconds.
- Lock-free reads. Multiple threads can call
notify()concurrently without contention. - Zero allocation on the hot path. Notify walks the handler list and dispatches without any heap allocation in the no-panic case.
- Focused scope. This is a local, in-process notification primitive. Not a message bus, not a distributed event system, not a pub/sub broker.
Documentation
docs/API.md— full API reference with examples per item.docs/PERFORMANCE.md— cost model, benchmarks, and concurrency characteristics..dev/ROADMAP.md— milestone plan to 1.0.CHANGELOG.md— release history.
Standards
- REPS (Rust Efficiency & Performance Standards) governs every decision.
See
REPS.md. - MSRV: Rust 1.85.
- Edition: 2024.
- Cross-platform: Linux, macOS, Windows.
License
Dual-licensed under either of:
- Apache License, Version 2.0 (LICENSE-APACHE)
- MIT License (LICENSE-MIT)
at your option.
Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
Copyright © 2026 James Gober. All rights reserved.