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}