ringdb/payload/mod.rs
1pub mod pod;
2pub mod serde;
3pub(crate) mod traits;
4
5pub use pod::{PodStore, PodStoreBuilder};
6pub use serde::{SerdeStore, SerdeStoreBuilder};
7pub use traits::PayloadBuilderOps;
8
9use crate::error::Result;
10
11// ─── Store traits ─────────────────────────────────────────────────────────────
12
13/// Implemented by all payload stores. Provides owned deserialization.
14///
15/// `SerdeStore<T>` deserializes via bincode.
16/// `PodStore<T>` copies `size_of::<T>()` bytes from the mmap.
17#[doc(hidden)]
18pub trait OwnedPayloadStore<T> {
19 fn fetch_owned(&self, id: u32) -> Result<T>;
20
21 fn fetch_many_owned(&self, ids: &[u32]) -> Result<Vec<T>> {
22 ids.iter().map(|&id| self.fetch_owned(id)).collect()
23 }
24}
25
26/// Implemented only by `PodStore<T>`. Provides zero-copy `&T` references.
27///
28/// This trait is the static gate for [`SealedRingDb::fetch_pod`]: the method
29/// only exists when `T::Store: RefPayloadStore<T>`, which is only true for
30/// types whose `#[derive(Payload)]` chose `storage = "pod"`.
31#[doc(hidden)]
32pub trait RefPayloadStore<T> {
33 fn fetch_ref(&self, id: u32) -> &T;
34
35 fn fetch_many_ref(&self, ids: &[u32]) -> Vec<&T> {
36 ids.iter().map(|&id| self.fetch_ref(id)).collect()
37 }
38}
39
40// ─── Payload trait ────────────────────────────────────────────────────────────
41
42/// Marker trait that ties a user type to its payload storage strategy.
43///
44/// Implement this trait via `#[derive(Payload)]` from the `ring-db-derive`
45/// crate (re-exported as `ringdb::Payload`).
46///
47/// Two storage strategies are available:
48///
49/// | Strategy | Attribute | Fetch return |
50/// |----------|-----------|--------------|
51/// | Serde (default) | *(none)* | `T` (owned, bincode) |
52/// | Pod | `#[payload(storage = "pod")]` | `&T` (zero-copy mmap) |
53pub trait Payload: Sized {
54 /// The read-only store produced by `Builder` and held inside
55 /// [`SealedRingDb`](crate::SealedRingDb).
56 type Store: OwnedPayloadStore<Self>;
57
58 /// The write-side builder held inside [`RingDb`](crate::RingDb) during
59 /// insertion. Consumed by `build()` to produce `Store`.
60 type Builder: PayloadBuilderOps<Self, Store = Self::Store>;
61
62 /// Create a fresh builder (called by `RingDb::new`).
63 fn make_builder() -> Result<Self::Builder>;
64
65 /// Load the store from a persisted directory (called by `RingDb::load`).
66 fn load_store(dir: &std::path::Path) -> Result<Self::Store>;
67}
68
69// ─── impl Payload for () ──────────────────────────────────────────────────────
70//
71// Allows `RingDb::new(config)` without specifying a payload type when none
72// is needed. Serde serializes `()` to 0 bytes, so the mmap stays empty.
73
74impl Payload for () {
75 type Store = SerdeStore<()>;
76 type Builder = SerdeStoreBuilder<()>;
77
78 fn make_builder() -> Result<Self::Builder> {
79 SerdeStoreBuilder::new()
80 }
81
82 fn load_store(dir: &std::path::Path) -> Result<Self::Store> {
83 SerdeStore::load(&dir.join("payloads.bin"), &dir.join("offsets.bin"))
84 }
85}