Skip to main content

photon_ring/
pod.rs

1// Copyright 2026 Photon Ring Contributors
2// SPDX-License-Identifier: Apache-2.0
3
4//! The [`Pod`] marker trait for seqlock-safe payload types.
5
6/// Marker trait for types safe to use with seqlock-stamped ring buffers.
7///
8/// A type is `Pod` ("Plain Old Data") if **every possible bit pattern**
9/// of `size_of::<T>()` bytes represents a valid value of `T`. This is
10/// stricter than [`Copy`] — it excludes types where certain bit patterns
11/// are undefined behavior, such as `bool` (only 0/1 valid), `char`
12/// (must be a valid Unicode scalar), `NonZero*` (must be nonzero), and
13/// references (must point to valid memory).
14///
15/// # Why this matters
16///
17/// The seqlock read protocol performs an optimistic non-atomic read that
18/// may observe a partially-written ("torn") value. If the torn bit pattern
19/// violates a type's validity invariant, this is undefined behavior even
20/// though the value is detected and discarded by the stamp check. `Pod`
21/// guarantees that no bit pattern is invalid, making torn reads harmless.
22///
23/// # Safety
24///
25/// Implementors must ensure:
26/// 1. `T` is `Copy` (no destructor, no move semantics).
27/// 2. `T` is `Send` (safe to transfer across threads).
28/// 3. Every possible bit pattern of `size_of::<T>()` bytes is a valid `T`.
29/// 4. `T` has no padding bytes that carry validity constraints.
30///
31/// # What types are NOT `Pod`?
32///
33/// | Type | Why | What to use instead |
34/// |---|---|---|
35/// | `bool` | Only 0 and 1 are valid | `u8` (0 = false, 1 = true) |
36/// | `char` | Must be valid Unicode scalar | `u32` |
37/// | `NonZero<u32>` | Zero is invalid | `u32` |
38/// | `Option<T>` | Discriminant has invalid patterns | `u8` sentinel (e.g., 255 = None) |
39/// | `enum` (Rust) | Only declared variants are valid | `u8` or `u32` with constants |
40/// | `&T`, `&str` | Pointer must be valid | Not supported — use value types |
41/// | `String`, `Vec` | Heap-allocated, has `Drop` | Fixed `[u8; N]` buffer |
42///
43/// # Converting real-world types
44///
45/// A common pattern: your domain model uses enums and `Option`, but the
46/// Photon Ring message struct uses plain integers:
47///
48/// ```rust
49/// // Domain type (NOT Pod — has Option and enum)
50/// // enum Side { Buy, Sell }
51/// // struct Order { price: f64, qty: u32, side: Side, tag: Option<u32> }
52///
53/// // Photon Ring message (Pod — all fields are plain numerics)
54/// #[repr(C)]
55/// #[derive(Clone, Copy)]
56/// struct OrderMsg {
57///     price: f64,
58///     qty: u32,
59///     side: u8,      // 0 = Buy, 1 = Sell
60///     tag: u32,      // 0 = None, nonzero = Some(value)
61///     _pad: [u8; 3], // explicit padding for alignment
62/// }
63/// unsafe impl photon_ring::Pod for OrderMsg {}
64///
65/// // Convert at the boundary:
66/// // let msg = OrderMsg { price: 100.0, qty: 10, side: 0, tag: 0, _pad: [0;3] };
67/// // publisher.publish(msg);
68/// ```
69///
70/// # Pre-implemented types
71///
72/// `Pod` is implemented for all primitive numeric types, arrays of `Pod`
73/// types, and tuples up to 12 elements of `Pod` types.
74///
75/// For user-defined structs, use `unsafe impl`:
76/// ```
77/// #[repr(C)]
78/// #[derive(Clone, Copy)]
79/// struct Quote {
80///     price: f64,
81///     volume: u32,
82///     _pad: u32,
83/// }
84///
85/// // SAFETY: Quote is #[repr(C)], all fields are plain numerics,
86/// // and every bit pattern is a valid Quote.
87/// unsafe impl photon_ring::Pod for Quote {}
88/// ```
89pub unsafe trait Pod: Copy + Send + 'static {}
90
91// Primitive numeric types — every bit pattern is valid
92unsafe impl Pod for u8 {}
93unsafe impl Pod for u16 {}
94unsafe impl Pod for u32 {}
95unsafe impl Pod for u64 {}
96unsafe impl Pod for u128 {}
97unsafe impl Pod for i8 {}
98unsafe impl Pod for i16 {}
99unsafe impl Pod for i32 {}
100unsafe impl Pod for i64 {}
101unsafe impl Pod for i128 {}
102unsafe impl Pod for f32 {}
103unsafe impl Pod for f64 {}
104unsafe impl Pod for usize {}
105unsafe impl Pod for isize {}
106
107// Arrays of Pod types
108unsafe impl<T: Pod, const N: usize> Pod for [T; N] {}
109
110// Tuples of Pod types (up to 12, matching standard library convention)
111unsafe impl Pod for () {}
112unsafe impl<A: Pod> Pod for (A,) {}
113unsafe impl<A: Pod, B: Pod> Pod for (A, B) {}
114unsafe impl<A: Pod, B: Pod, C: Pod> Pod for (A, B, C) {}
115unsafe impl<A: Pod, B: Pod, C: Pod, D: Pod> Pod for (A, B, C, D) {}
116unsafe impl<A: Pod, B: Pod, C: Pod, D: Pod, E: Pod> Pod for (A, B, C, D, E) {}
117unsafe impl<A: Pod, B: Pod, C: Pod, D: Pod, E: Pod, F: Pod> Pod for (A, B, C, D, E, F) {}
118unsafe impl<A: Pod, B: Pod, C: Pod, D: Pod, E: Pod, F: Pod, G: Pod> Pod for (A, B, C, D, E, F, G) {}
119unsafe impl<A: Pod, B: Pod, C: Pod, D: Pod, E: Pod, F: Pod, G: Pod, H: Pod> Pod
120    for (A, B, C, D, E, F, G, H)
121{
122}
123unsafe impl<A: Pod, B: Pod, C: Pod, D: Pod, E: Pod, F: Pod, G: Pod, H: Pod, I: Pod> Pod
124    for (A, B, C, D, E, F, G, H, I)
125{
126}
127unsafe impl<A: Pod, B: Pod, C: Pod, D: Pod, E: Pod, F: Pod, G: Pod, H: Pod, I: Pod, J: Pod> Pod
128    for (A, B, C, D, E, F, G, H, I, J)
129{
130}
131unsafe impl<A: Pod, B: Pod, C: Pod, D: Pod, E: Pod, F: Pod, G: Pod, H: Pod, I: Pod, J: Pod, K: Pod>
132    Pod for (A, B, C, D, E, F, G, H, I, J, K)
133{
134}
135unsafe impl<
136        A: Pod,
137        B: Pod,
138        C: Pod,
139        D: Pod,
140        E: Pod,
141        F: Pod,
142        G: Pod,
143        H: Pod,
144        I: Pod,
145        J: Pod,
146        K: Pod,
147        L: Pod,
148    > Pod for (A, B, C, D, E, F, G, H, I, J, K, L)
149{
150}