photon_ring/lib.rs
1// Copyright 2026 Photon Ring Contributors
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4//! # Photon Ring
5//!
6//! Ultra-low-latency SPMC/MPMC pub/sub using stamped ring buffers.
7//!
8//! `no_std` compatible (requires `alloc`). The [`topology`] module uses
9//! OS threads and is available on Linux, macOS, Windows, and other
10//! supported platforms.
11//!
12//! ## Key design
13//!
14//! - **Seqlock per slot** — stamp and payload share a cache line; readers never
15//! take a lock, writers never allocate.
16//! - **`T: Pod`** — restricts payloads to plain-old-data types that carry no
17//! padding and where every bit pattern is valid, so a torn seqlock read
18//! yields a value that is discarded rather than an invalid one.
19//! - **Per-consumer cursor** — zero contention between subscribers.
20//! - **Single-producer** — no write-side synchronisation; the seqlock invariant
21//! is upheld by `&mut self` on [`Publisher::publish`].
22//! - **`atomic-slots` feature** — formally sound variant that uses `AtomicU64` stripes
23//! instead of `write_volatile`. Zero cost on x86-64. See the `atomic-slots` feature flag.
24//! - **Arbitrary capacity** — any ring size >= 2 via Lemire fastmod; power-of-two
25//! uses bitwise AND (zero regression).
26//! - **Companion crates** — `photon-ring-async` for runtime-agnostic async wrappers,
27//! `photon-ring-metrics` for framework-agnostic observability.
28//!
29//! ## Which ring
30//!
31//! - [`channel()`] — lossy `Pod` broadcast; the publisher never blocks, and a
32//! subscriber that falls behind observes `Lagged { skipped }`.
33//! - [`channel_bounded()`] — per-consumer contracts on one ring:
34//! [`subscribe()`](Subscribable::subscribe) gates the publisher and loses
35//! nothing, [`subscribe_lossy()`](Subscribable::subscribe_lossy) can never
36//! stall it.
37//! - [`channel_mpmc()`] — many producing threads; delivery is lossy only.
38//! - [`event_channel()`] — payloads that own heap data (`String`, `Vec`,
39//! enums); slots are mutated in place and every subscriber gates the
40//! publisher.
41//! - [`Photon`] / [`TypedBus`] — string-keyed topics, each an independent
42//! lossy ring.
43//! - [`topology`] — dedicated-thread pipelines and terminal consumers.
44//!
45//! ## Quick start
46//!
47//! ```
48//! // Low-level SPMC channel
49//! let (mut pub_, subs) = photon_ring::channel::<u64>(64);
50//! let mut sub = subs.subscribe();
51//! pub_.publish(42);
52//! assert_eq!(sub.try_recv(), Ok(42));
53//!
54//! // Named-topic bus
55//! let bus = photon_ring::Photon::<u64>::new(64);
56//! let mut p = bus.publisher("topic-a");
57//! let mut s = bus.subscribe("topic-a");
58//! p.publish(7);
59//! assert_eq!(s.try_recv(), Ok(7));
60//! ```
61
62#![no_std]
63
64extern crate alloc;
65
66#[cfg(any(
67 target_os = "linux",
68 target_os = "macos",
69 target_os = "windows",
70 target_os = "freebsd",
71 target_os = "netbsd",
72 target_os = "android",
73))]
74pub mod affinity;
75pub mod barrier;
76mod bus;
77pub mod channel;
78pub mod event;
79#[cfg(all(target_os = "linux", feature = "hugepages"))]
80pub mod mem;
81mod pod;
82pub(crate) mod ring;
83mod shutdown;
84pub(crate) mod slot;
85#[cfg(any(
86 target_os = "linux",
87 target_os = "macos",
88 target_os = "windows",
89 target_os = "freebsd",
90 target_os = "netbsd",
91 target_os = "android",
92))]
93pub mod topology;
94mod typed_bus;
95pub mod wait;
96
97pub use barrier::DependencyBarrier;
98pub use bus::Photon;
99pub use channel::{
100 channel, channel_bounded, channel_mpmc, Drain, MpPublisher, PublishError, Publisher,
101 Subscribable, Subscriber, TryRecvError,
102};
103pub use event::{event_channel, EventPublisher, EventSubscribable, EventSubscriber};
104pub use pod::Pod;
105pub use ring::Padded;
106
107/// Derive macro for the [`Pod`] trait. Requires the `derive` feature.
108///
109/// ```ignore
110/// #[derive(photon_ring::DerivePod, Clone, Copy)]
111/// #[repr(C)]
112/// struct Quote { price: f64, volume: u32 }
113/// ```
114#[cfg(feature = "derive")]
115pub use photon_ring_derive::Pod as DerivePod;
116
117/// Derive macro that generates a Pod-compatible wire struct from a domain struct.
118///
119/// Given a struct with `bool`, `Option<numeric>`, `usize`/`isize`, and
120/// `#[repr(u8)]` enum fields, generates `{Name}Wire` plus `From` conversions.
121/// Structs without enum fields get safe `From` impls in both directions;
122/// structs with enum fields get `From<Domain> for Wire` (safe) and
123/// `Wire::into_domain()` (unsafe). Requires the `derive` feature.
124///
125/// ```ignore
126/// #[derive(photon_ring::DeriveMessage)]
127/// struct Order { price: f64, side: Side, filled: bool, tag: Option<u32> }
128/// // Generates: OrderWire, From<Order> for OrderWire, From<OrderWire> for Order
129/// ```
130#[cfg(feature = "derive")]
131pub use photon_ring_derive::Message as DeriveMessage;
132
133pub use shutdown::Shutdown;
134pub use typed_bus::TypedBus;
135pub use wait::WaitStrategy;