Skip to main content

plugmem_core/
id.rs

1//! Typed identifiers.
2//!
3//! All ids are `u32`, allocated monotonically, never reused (journal replay
4//! stays deterministic; holes after a purge are normal). `0` is a valid id;
5//! "no value" is encoded as [`u32::MAX`] — every newtype exposes it as its
6//! `NONE` constant. The 4.29-billion ceiling per kind is far above the 1M
7//! capacity passport.
8
9/// The raw "no value" sentinel shared by every id kind.
10pub const NONE_U32: u32 = u32::MAX;
11
12/// Declares one id newtype with the shared sentinel plumbing.
13macro_rules! id_type {
14    ($(#[$doc:meta])* $name:ident) => {
15        $(#[$doc])*
16        #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
17        #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
18        pub struct $name(pub u32);
19
20        impl $name {
21            /// The "no value" sentinel ([`u32::MAX`]).
22            pub const NONE: Self = Self(NONE_U32);
23
24            /// `true` when this is the [`Self::NONE`] sentinel.
25            pub fn is_none(self) -> bool {
26                self.0 == NONE_U32
27            }
28
29            /// `Some(self)` for a real id, `None` for the sentinel.
30            pub fn some(self) -> Option<Self> {
31                if self.is_none() { None } else { Some(self) }
32            }
33
34            /// Collapses an optional id back into the sentinel encoding.
35            pub fn from_opt(opt: Option<Self>) -> Self {
36                opt.unwrap_or(Self::NONE)
37            }
38        }
39    };
40}
41
42id_type! {
43    /// Identifier of a fact — the unit of memory.
44    FactId
45}
46
47id_type! {
48    /// Identifier of an entity — a graph node created lazily on first
49    /// mention.
50    EntityId
51}