Skip to main content

registry_io/
lib.rs

1//! # registry-io
2//!
3//! High-performance event and callback registry primitive for Rust.
4//!
5//! `registry-io` provides a focused alternative to channel-based notification
6//! when several components need to react to the same in-process event with
7//! the lowest possible dispatch overhead. The hot path is **lock-free**,
8//! **allocation-free**, and **panic-isolating**.
9//!
10//! # Design philosophy
11//!
12//! - **Sync-first.** The default registry runs handlers inline on the
13//!   calling thread, with sub-microsecond dispatch overhead.
14//! - **Lock-free reads.** Multiple threads can fire [`SyncRegistry::notify`]
15//!   concurrently without serialization.
16//! - **Zero allocation on the hot path.** `notify` walks an
17//!   [`arc_swap::ArcSwap`] snapshot of `Arc<dyn Fn>` pointers and dispatches
18//!   each one — no allocations along the no-panic path.
19//! - **Panic isolation.** A panic in one handler is caught and does **not**
20//!   stop sibling handlers or propagate to the caller.
21//! - **Priority ordering.** Handlers may be registered with a priority value;
22//!   higher priorities fire first, ties broken in registration order.
23//! - **RAII unregistration.** [`HandlerGuard`] cleans up automatically.
24//!
25//! # Quick start
26//!
27//! ```
28//! use std::sync::Arc;
29//! use std::sync::atomic::{AtomicU32, Ordering};
30//! use registry_io::SyncRegistry;
31//!
32//! let registry: SyncRegistry<u32> = SyncRegistry::new();
33//! let counter = Arc::new(AtomicU32::new(0));
34//!
35//! let sink = Arc::clone(&counter);
36//! let id = registry.register(move |value| {
37//!     sink.fetch_add(*value, Ordering::Relaxed);
38//! });
39//!
40//! registry.notify(&5);
41//! registry.notify(&7);
42//! assert_eq!(counter.load(Ordering::Relaxed), 12);
43//!
44//! assert!(registry.unregister(id));
45//! ```
46//!
47//! # Feature flags
48//!
49//! - `std` (default) — enables the standard library. Required for sync and
50//!   async registries.
51//! - `sync` (default) — exposes [`SyncRegistry`]. Implies `std`.
52//! - `async` — reserved for a future release; exposes `AsyncRegistry` for
53//!   `async fn` handlers. Implies `std`.
54//! - `hybrid` — activates both `sync` and `async`.
55//!
56//! # Out of scope
57//!
58//! `registry-io` is a local, in-process primitive. It is **not** a pub/sub
59//! broker, **not** a message bus, and **not** a replacement for channels
60//! when you need cross-process or cross-network delivery with backpressure.
61//! See the project README for a list of when **not** to use it.
62//!
63//! # License
64//!
65//! Dual-licensed under Apache-2.0 OR MIT.
66
67#![doc(html_root_url = "https://docs.rs/registry-io/1.0.0")]
68#![cfg_attr(docsrs, feature(doc_cfg))]
69#![cfg_attr(not(feature = "std"), no_std)]
70#![deny(missing_docs)]
71#![deny(unsafe_op_in_unsafe_fn)]
72#![deny(unused_must_use)]
73#![deny(unused_results)]
74#![deny(clippy::unwrap_used)]
75#![deny(clippy::expect_used)]
76#![deny(clippy::todo)]
77#![deny(clippy::unimplemented)]
78#![deny(clippy::print_stdout)]
79#![deny(clippy::print_stderr)]
80#![deny(clippy::dbg_macro)]
81#![deny(clippy::undocumented_unsafe_blocks)]
82#![deny(clippy::missing_safety_doc)]
83#![warn(clippy::pedantic)]
84#![allow(clippy::module_name_repetitions)]
85
86extern crate alloc;
87
88#[cfg(feature = "std")]
89extern crate std;
90
91mod handler_id;
92
93#[cfg(any(feature = "sync", feature = "async"))]
94mod panic;
95
96#[cfg(feature = "async")]
97mod future_ext;
98
99#[cfg(feature = "sync")]
100pub mod sync;
101
102#[cfg(feature = "async")]
103#[path = "async_registry/mod.rs"]
104pub mod r#async;
105
106pub use handler_id::HandlerId;
107
108#[cfg(any(feature = "sync", feature = "async"))]
109#[cfg_attr(docsrs, doc(cfg(any(feature = "sync", feature = "async"))))]
110pub use panic::PanicInfo;
111
112#[cfg(feature = "sync")]
113#[cfg_attr(docsrs, doc(cfg(feature = "sync")))]
114pub use sync::{HandlerGuard, SyncRegistry};
115
116#[cfg(feature = "async")]
117#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
118pub use r#async::{AsyncHandlerGuard, AsyncRegistry};
119
120/// Crate version string, populated by Cargo at build time.
121///
122/// # Examples
123///
124/// ```
125/// // VERSION is the canonical place to read the running crate version,
126/// // for diagnostic logging or version-gated behavior.
127/// assert!(!registry_io::VERSION.is_empty());
128/// assert!(registry_io::VERSION.starts_with("0.") || registry_io::VERSION.starts_with("1."));
129/// ```
130pub const VERSION: &str = env!("CARGO_PKG_VERSION");