Skip to main content

liminal_protocol/outcome/
parking.rs

1use crate::wire::ConversationId;
2
3/// Configuration-limit selector used by parking shape validation.
4#[derive(Clone, Copy, Debug, PartialEq, Eq)]
5pub enum ParkingLimitField {
6    /// Per-conversation parked-row limit.
7    N,
8    /// Per-conversation parked-byte limit.
9    C,
10    /// SDK-wide recoverable-conversation limit.
11    P,
12    /// SDK-wide parked-row limit.
13    G,
14    /// SDK-wide parked-byte limit.
15    D,
16    /// Participant request-byte limit.
17    R,
18    /// Charged parked-row byte bound.
19    B,
20    /// Recovery request-entry schema bytes.
21    RE,
22    /// Negotiated wire-frame byte limit.
23    WF,
24}
25
26/// Exact operands for the only checked-product failure.
27#[derive(Clone, Copy, Debug, PartialEq, Eq)]
28pub struct CheckedMultiplyOverflow {
29    /// Left multiplication operand.
30    pub left: u64,
31    /// Right multiplication operand.
32    pub right: u64,
33}
34
35impl CheckedMultiplyOverflow {
36    /// The failed operation is always multiplication.
37    #[must_use]
38    pub const fn operation(self) -> CheckedOperation {
39        let _ = self;
40        CheckedOperation::Multiply
41    }
42
43    /// An overflow has no checked result.
44    #[must_use]
45    pub const fn checked_result(self) -> Option<u64> {
46        let _ = self;
47        None
48    }
49
50    /// The tagged body always denotes overflow.
51    #[must_use]
52    pub const fn overflow(self) -> bool {
53        let _ = self;
54        true
55    }
56}
57
58/// Operation selector for a checked-product failure.
59#[derive(Clone, Copy, Debug, PartialEq, Eq)]
60pub enum CheckedOperation {
61    /// Checked multiplication.
62    Multiply,
63}
64
65/// Exact nine-way parking configuration-shape violation.
66#[derive(Clone, Copy, Debug, PartialEq, Eq)]
67pub enum ParkingShapeViolation {
68    /// One of the signed limits is zero.
69    NonzeroLimit {
70        /// Offending signed field.
71        field: ParkingLimitField,
72        /// Actual value, which is zero for this variant.
73        actual: u64,
74        /// Required minimum, which is one for this variant.
75        required_minimum: u64,
76    },
77    /// Recovery request-entry schema is not the fixed width.
78    RecoveryEntrySchemaBytes {
79        /// Configured request-entry width.
80        actual: u64,
81        /// Required request-entry width of sixteen bytes.
82        required: u64,
83    },
84    /// Wire frame is too small for one participant frame.
85    WireSchemaBytes {
86        /// Configured wire-frame limit.
87        actual: u64,
88        /// Required participant-frame schema bytes.
89        required: u64,
90    },
91    /// Effective request limit is too small for one request schema.
92    RequestSchemaBytes {
93        /// Configured participant request limit.
94        configured_request_limit: u64,
95        /// Configured wire-frame limit.
96        wire_frame_limit: u64,
97        /// Effective request limit `min(R, WF)`.
98        actual: u64,
99        /// Required participant-request schema bytes.
100        required: u64,
101    },
102    /// Charged row bound is below request plus row metadata.
103    RowSchemaBytes {
104        /// Configured participant request limit.
105        request_limit: u64,
106        /// Fixed row-metadata bytes.
107        row_metadata_bytes: u64,
108        /// Configured charged row byte bound.
109        actual: u64,
110        /// Exact widened required bytes.
111        required: u128,
112    },
113    /// A required limit product overflowed `u64`.
114    CheckedProduct(CheckedMultiplyOverflow),
115    /// Per-conversation bytes are below `N * B`.
116    RowBytesBound {
117        /// Per-conversation row limit.
118        left: u64,
119        /// Charged row byte bound.
120        right: u64,
121        /// Checked `N * B` product.
122        checked_product: u64,
123        /// Configured per-conversation byte limit.
124        actual: u64,
125    },
126    /// SDK-wide bytes are below `G * B`.
127    SdkBytesBound {
128        /// SDK-wide row limit.
129        left: u64,
130        /// Charged row byte bound.
131        right: u64,
132        /// Checked `G * B` product.
133        checked_product: u64,
134        /// Configured SDK-wide byte limit.
135        actual: u64,
136    },
137    /// Recoverable conversation slots exceed the connection capability.
138    RecoverableSlots {
139        /// Configured recoverable-conversation count.
140        actual: u64,
141        /// Negotiated participant-conversation slots per connection.
142        limit: u64,
143    },
144}
145
146/// Startup parking configuration is invalid before handshake sizing.
147#[derive(Clone, Copy, Debug, PartialEq, Eq)]
148pub struct ParticipantParkingConfigurationInvalid {
149    /// First failing shape dimension and its exact operands.
150    pub violation: ParkingShapeViolation,
151}
152
153/// Exact widened operands shared by recovery-handshake size failures.
154#[derive(Clone, Copy, Debug, PartialEq, Eq)]
155pub struct HandshakeSizeOperands {
156    /// Maximum recovery entries `P`.
157    pub max_entries: u64,
158    /// Exact widened `u128(RF) + u128(RC(P))` bytes.
159    pub framing_bytes: u128,
160    /// Recovery request-entry schema bytes `RE`.
161    pub request_entry_bytes: u64,
162    /// Recovery response status-entry schema bytes `SE`.
163    pub response_entry_bytes: u64,
164    /// Recovery error-response schema bytes `EE`.
165    pub error_response_bytes: u64,
166    /// Exact widened request bytes `RH(P)`.
167    pub request_encoded_bytes: u128,
168    /// Exact widened response bytes `SH(P)`.
169    pub response_encoded_bytes: u128,
170}
171
172/// Recovery-handshake dimension that exceeded a signed limit.
173#[derive(Clone, Copy, Debug, PartialEq, Eq)]
174pub enum RecoveryHandshakeDimension {
175    /// Recovery request exceeded `R`.
176    RequestBytes,
177    /// Recovery request exceeded `WF`.
178    RequestWireFrameBytes,
179    /// Recovery response exceeded `WF`.
180    ResponseWireFrameBytes,
181}
182
183/// Initial-phase recovery handshake cannot fit the signed limits.
184#[derive(Clone, Copy, Debug, PartialEq, Eq)]
185pub struct ParticipantRecoveryHandshakeTooLarge {
186    /// Maximum recovery entries `P`.
187    pub max_entries: u64,
188    /// Exact widened `u128(RF) + u128(RC(P))` bytes.
189    pub framing_bytes: u128,
190    /// Recovery request-entry schema bytes `RE`.
191    pub request_entry_bytes: u64,
192    /// Recovery response status-entry schema bytes `SE`.
193    pub response_entry_bytes: u64,
194    /// Recovery error-response schema bytes `EE`.
195    pub error_response_bytes: u64,
196    /// Exact widened request bytes `RH(P)`.
197    pub request_encoded_bytes: u128,
198    /// Exact widened response bytes `SH(P)`.
199    pub response_encoded_bytes: u128,
200    /// Signed participant request limit `R`.
201    pub request_limit: u64,
202    /// Signed negotiated wire-frame limit `WF`.
203    pub wire_frame_limit: u64,
204    /// First failing handshake dimension.
205    pub dimension: RecoveryHandshakeDimension,
206}
207
208/// Parked rows are incompatible with replacement SDK configuration.
209#[derive(Clone, Copy, Debug, PartialEq, Eq)]
210pub enum SdkParkingCapacityIncompatible {
211    /// One of the replacement signed limits is zero.
212    NonzeroLimit {
213        /// Offending signed field.
214        field: ParkingLimitField,
215        /// Actual value, which is zero for this variant.
216        actual: u64,
217        /// Required minimum, which is one for this variant.
218        required_minimum: u64,
219    },
220    /// Recovery request-entry schema is not the fixed width.
221    RecoveryEntrySchemaBytes {
222        /// Configured request-entry width.
223        actual: u64,
224        /// Required request-entry width.
225        required: u64,
226    },
227    /// Wire frame is too small for one participant frame.
228    WireSchemaBytes {
229        /// Configured wire-frame limit.
230        actual: u64,
231        /// Required participant-frame schema bytes.
232        required: u64,
233    },
234    /// Effective request limit is too small for one request schema.
235    RequestSchemaBytes {
236        /// Configured participant request limit.
237        configured_request_limit: u64,
238        /// Configured wire-frame limit.
239        wire_frame_limit: u64,
240        /// Effective request limit `min(R, WF)`.
241        actual: u64,
242        /// Required participant-request schema bytes.
243        required: u64,
244    },
245    /// Charged row bound is below request plus row metadata.
246    RowSchemaBytes {
247        /// Configured participant request limit.
248        request_limit: u64,
249        /// Fixed row-metadata bytes.
250        row_metadata_bytes: u64,
251        /// Configured charged row byte bound.
252        actual: u64,
253        /// Exact widened required bytes.
254        required: u128,
255    },
256    /// A required replacement limit product overflowed `u64`.
257    CheckedProduct(CheckedMultiplyOverflow),
258    /// Per-conversation bytes are below `N * B`.
259    RowBytesBound {
260        /// Per-conversation row limit.
261        left: u64,
262        /// Charged row byte bound.
263        right: u64,
264        /// Checked `N * B` product.
265        checked_product: u64,
266        /// Configured per-conversation byte limit.
267        actual: u64,
268    },
269    /// SDK-wide bytes are below `G * B`.
270    SdkBytesBound {
271        /// SDK-wide row limit.
272        left: u64,
273        /// Charged row byte bound.
274        right: u64,
275        /// Checked `G * B` product.
276        checked_product: u64,
277        /// Configured SDK-wide byte limit.
278        actual: u64,
279    },
280    /// Recoverable conversation slots exceed connection capability.
281    RecoverableSlots {
282        /// Configured recoverable-conversation count.
283        actual: u64,
284        /// Negotiated participant-conversation slots per connection.
285        limit: u64,
286    },
287    /// Existing rows exceed replacement per-conversation row capacity.
288    ConversationRows {
289        /// Conversation with incompatible retained rows.
290        conversation_id: ConversationId,
291        /// Existing retained rows.
292        occupied: u64,
293        /// Replacement per-conversation row limit.
294        limit: u64,
295    },
296    /// Existing bytes exceed replacement per-conversation byte capacity.
297    ConversationBytes {
298        /// Conversation with incompatible retained bytes.
299        conversation_id: ConversationId,
300        /// Existing charged retained bytes.
301        occupied: u64,
302        /// Replacement per-conversation byte limit.
303        limit: u64,
304    },
305    /// Existing parked conversations exceed replacement SDK capacity.
306    SdkConversations {
307        /// Existing parked-conversation count.
308        occupied: u64,
309        /// Replacement SDK conversation limit.
310        limit: u64,
311    },
312    /// Existing rows exceed replacement SDK row capacity.
313    SdkRows {
314        /// Existing SDK-wide retained rows.
315        occupied: u64,
316        /// Replacement SDK row limit.
317        limit: u64,
318    },
319    /// Existing bytes exceed replacement SDK byte capacity.
320    SdkBytes {
321        /// Existing SDK-wide charged retained bytes.
322        occupied: u64,
323        /// Replacement SDK byte limit.
324        limit: u64,
325    },
326    /// One retained request exceeds replacement effective request bytes.
327    RequestBytes {
328        /// Conversation holding the retained request.
329        conversation_id: ConversationId,
330        /// Durable order of the retained request.
331        park_order: u64,
332        /// Complete encoded participant request bytes.
333        actual: u64,
334        /// Replacement effective request limit `min(R, WF)`.
335        limit: u64,
336    },
337    /// Recovery request exceeds replacement participant request bytes.
338    RecoveryHandshakeRequestBytes {
339        /// Complete exact widened sizing operands.
340        operands: HandshakeSizeOperands,
341        /// Replacement participant request limit.
342        limit: u64,
343    },
344    /// Recovery request exceeds replacement wire-frame bytes.
345    RecoveryHandshakeRequestWireFrameBytes {
346        /// Complete exact widened sizing operands.
347        operands: HandshakeSizeOperands,
348        /// Replacement wire-frame limit.
349        limit: u64,
350    },
351    /// Recovery response exceeds replacement wire-frame bytes.
352    RecoveryHandshakeResponseWireFrameBytes {
353        /// Complete exact widened sizing operands.
354        operands: HandshakeSizeOperands,
355        /// Replacement wire-frame limit.
356        limit: u64,
357    },
358}