bibeam_core/ids.rs
1#![forbid(unsafe_code)]
2//! ULID newtypes for the `BiBeam` identity space.
3//!
4//! Four distinct wrappers — [`PeerId`], [`NodeId`], [`CohortId`], [`ChainId`]
5//! — sit over [`ulid::Ulid`] so the type system can distinguish a peer from a
6//! node from a cohort from a multi-hop forwarder chain, even though they all
7//! share the same wire encoding (a 128-bit Crockford-Base32 ULID).
8
9use core::{fmt, str::FromStr};
10
11use serde::{Deserialize, Serialize};
12use ulid::Ulid;
13
14macro_rules! ulid_newtype {
15 (
16 $(#[$doc:meta])*
17 $name:ident
18 ) => {
19 $(#[$doc])*
20 #[derive(
21 Clone,
22 Copy,
23 Debug,
24 PartialEq,
25 Eq,
26 Hash,
27 PartialOrd,
28 Ord,
29 Serialize,
30 Deserialize,
31 )]
32 #[serde(transparent)]
33 pub struct $name(pub Ulid);
34
35 impl $name {
36 /// Generate a fresh identifier using the system clock plus
37 /// [`ulid::Ulid::new`]'s default RNG.
38 #[must_use]
39 #[allow(
40 clippy::new_without_default,
41 reason = "Default::default() returns Ulid::nil() — a zero ULID — \
42 which is observably different from a freshly generated ULID; \
43 we deliberately do not derive Default to avoid that surprise."
44 )]
45 pub fn new() -> Self {
46 Self(Ulid::new())
47 }
48
49 /// Borrow the underlying [`Ulid`].
50 #[must_use]
51 pub const fn as_ulid(&self) -> &Ulid {
52 &self.0
53 }
54
55 /// Consume the newtype and return the underlying [`Ulid`].
56 #[must_use]
57 pub const fn into_ulid(self) -> Ulid {
58 self.0
59 }
60 }
61
62 impl fmt::Display for $name {
63 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
64 fmt::Display::fmt(&self.0, f)
65 }
66 }
67
68 impl FromStr for $name {
69 type Err = ulid::DecodeError;
70
71 fn from_str(s: &str) -> Result<Self, Self::Err> {
72 Ulid::from_string(s).map(Self)
73 }
74 }
75 };
76}
77
78ulid_newtype! {
79 /// Identifier for a single remote peer in the `BiBeam` mesh.
80 PeerId
81}
82
83ulid_newtype! {
84 /// Identifier for a local node (this process's view of itself).
85 NodeId
86}
87
88ulid_newtype! {
89 /// Identifier for a cohort — a logical grouping of peers that share a
90 /// trust or routing scope.
91 CohortId
92}
93
94ulid_newtype! {
95 /// Identifier for a multi-hop forwarder chain.
96 ///
97 /// Coordinator-issued opaque handle that every forwarder along a
98 /// `MatchResponse::MultiHopAssignment` chain uses to look up the
99 /// row in its lease table that authorises a given packet flow.
100 /// Lives independently of [`CohortId`] because one cohort can have
101 /// many concurrent multi-hop assignments, and one chain may serve
102 /// peers from different cohorts at different times.
103 ChainId
104}