Skip to main content

liminal_protocol/wire/
primitives.rs

1/// Stable conversation identifier.
2pub type ConversationId = u64;
3
4/// Permanent participant identifier and base identity index.
5pub type ParticipantId = u64;
6
7/// Permanent participant index used by participant-scoped progress accounting.
8pub type ParticipantIndex = u64;
9
10/// Nonzero participant capability or retired generation.
11#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
12pub struct Generation(core::num::NonZeroU64);
13
14impl Generation {
15    /// Canonical first participant generation.
16    pub const ONE: Self = Self(core::num::NonZeroU64::MIN);
17
18    /// Creates a generation, returning `None` for the forbidden zero value.
19    #[must_use]
20    pub const fn new(value: u64) -> Option<Self> {
21        match core::num::NonZeroU64::new(value) {
22            Some(value) => Some(Self(value)),
23            None => None,
24        }
25    }
26
27    /// Returns the nonzero wire value.
28    #[must_use]
29    pub const fn get(self) -> u64 {
30        self.0.get()
31    }
32}
33
34/// Conversation delivery sequence.
35pub type DeliverySeq = u64;
36
37/// Serialized conversation transaction order.
38pub type TransactionOrder = u64;
39
40/// Observer refusal/progress epoch.
41pub type ObserverEpoch = u64;
42
43/// Marker-settlement refusal/clearing epoch.
44///
45/// Deliberately distinct from [`ObserverEpoch`]: the settlement family is
46/// cleared by another participant's record admission or by boot drain, never by
47/// observer progress, so the two epochs are never comparable even though both
48/// serialize as `u64` (participant contract ยง0.16 condition 2).
49pub type SettlementEpoch = u64;
50
51/// Participant protocol version carried in every inner frame prefix.
52#[derive(Clone, Copy, Debug, PartialEq, Eq)]
53pub struct ProtocolVersion {
54    /// Major version.
55    pub major: u16,
56    /// Minor version.
57    pub minor: u16,
58}
59
60impl ProtocolVersion {
61    /// Participant protocol v1.0.
62    pub const V1: Self = Self { major: 1, minor: 0 };
63
64    /// Creates a protocol version.
65    #[must_use]
66    pub const fn new(major: u16, minor: u16) -> Self {
67        Self { major, minor }
68    }
69}
70
71/// Server and connection identity for one accepted connection incarnation.
72#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
73pub struct ConnectionIncarnation {
74    /// Durable server incarnation.
75    pub server_incarnation: u64,
76    /// Connection ordinal within that server incarnation.
77    pub connection_ordinal: u64,
78}
79
80impl ConnectionIncarnation {
81    /// Creates a connection incarnation.
82    #[must_use]
83    pub const fn new(server_incarnation: u64, connection_ordinal: u64) -> Self {
84        Self {
85            server_incarnation,
86            connection_ordinal,
87        }
88    }
89}
90
91/// Immutable participant binding epoch.
92#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
93pub struct BindingEpoch {
94    /// Connection that owns the binding.
95    pub connection_incarnation: ConnectionIncarnation,
96    /// Capability generation captured by the binding commit.
97    pub capability_generation: Generation,
98}
99
100impl BindingEpoch {
101    /// Creates a binding epoch.
102    #[must_use]
103    pub const fn new(
104        connection_incarnation: ConnectionIncarnation,
105        capability_generation: Generation,
106    ) -> Self {
107        Self {
108            connection_incarnation,
109            capability_generation,
110        }
111    }
112}
113
114macro_rules! fixed_credential {
115    ($(#[$meta:meta])* $name:ident, $length:expr) => {
116        $(#[$meta])*
117        #[derive(Clone, Copy, PartialEq, Eq, Hash)]
118        pub struct $name([u8; $length]);
119
120        /// Names the type and its length, never its bytes: a credential
121        /// reaches logs and error text through `{:?}`.
122        impl core::fmt::Debug for $name {
123            fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
124                write!(formatter, "{}({} bytes)", stringify!($name), $length)
125            }
126        }
127
128        impl $name {
129            /// Creates the fixed-width value from its canonical bytes.
130            #[must_use]
131            pub const fn new(bytes: [u8; $length]) -> Self {
132                Self(bytes)
133            }
134
135            /// Returns the canonical fixed-width bytes.
136            #[must_use]
137            pub const fn into_bytes(self) -> [u8; $length] {
138                self.0
139            }
140
141            /// Borrows the canonical fixed-width bytes.
142            #[must_use]
143            pub const fn as_bytes(&self) -> &[u8; $length] {
144                &self.0
145            }
146        }
147    };
148}
149
150fixed_credential!(
151    /// Single-purpose enrollment attempt token.
152    EnrollmentToken,
153    16
154);
155fixed_credential!(
156    /// Single-purpose credential-attach attempt token.
157    AttachAttemptToken,
158    16
159);
160fixed_credential!(
161    /// Single-purpose explicit-detach attempt token.
162    DetachAttemptToken,
163    16
164);
165fixed_credential!(
166    /// Single-purpose terminal Leave attempt token.
167    LeaveAttemptToken,
168    16
169);
170fixed_credential!(
171    /// Single-purpose ordinary record-admission attempt token.
172    RecordAdmissionAttemptToken,
173    16
174);
175fixed_credential!(
176    /// Participant attach secret.
177    AttachSecret,
178    32
179);