1use alloc::vec::Vec;
2
3use super::{
4 AttachAttemptToken, AttachSecret, BindingEpoch, ClientDiscriminant, ClientRequest,
5 CloseCauseTag, ConnectionIncarnation, CredentialAttachRequest, DecodeClass, DetachAttemptToken,
6 DetachRequest, DetachedCause, DiedCause, EnrollmentRequest, EnrollmentToken, Generation,
7 LeaveAttemptToken, LeaveRequest, MarkerAck, ObserverRecoveryHandshake, ObserverRefusal,
8 ParticipantAck, ParticipantDelivery, ParticipantRecord, ParticipantTransportRejected,
9 ProtocolVersion, PushDiscriminant, RecordAdmission, RecordAdmissionAttemptToken, RecordKind,
10 ServerDiscriminant, ServerPush, ServerValue, SettlementQuery, TransportRejectionReason,
11};
12
13pub const PARTICIPANT_FRAME_TYPE: u8 = 0x1A;
15
16pub const GENERIC_HEADER_LEN: usize = 10;
18
19pub const PARTICIPANT_PREFIX_LEN: usize = 6;
21
22pub const PARTICIPANT_FRAME_OVERHEAD: usize = GENERIC_HEADER_LEN + PARTICIPANT_PREFIX_LEN;
24
25pub const FRAME_MAX: u64 = 4_294_967_305;
27
28pub const PRECAP_PARTICIPANT_FRAME_MAX: u64 = 1_048_576;
30
31pub const MIN_PARTICIPANT_FRAME_MAX: u64 = 16;
33
34#[derive(Clone, Copy, Debug, PartialEq, Eq)]
36pub enum ReceiverDirection {
37 Server,
39 Client,
41}
42
43#[derive(Clone, Copy, Debug, PartialEq, Eq)]
48pub struct ValidatedFrameLimit(u64);
49
50impl ValidatedFrameLimit {
51 pub const fn new(max_frame_bytes: u64) -> Result<Self, CodecError> {
58 if max_frame_bytes < MIN_PARTICIPANT_FRAME_MAX || max_frame_bytes > FRAME_MAX {
59 return Err(CodecError::InvalidFrameLimit { max_frame_bytes });
60 }
61 Ok(Self(max_frame_bytes))
62 }
63
64 #[must_use]
66 pub const fn get(self) -> u64 {
67 self.0
68 }
69}
70
71#[derive(Clone, Copy, Debug, PartialEq, Eq)]
73pub enum AuthenticationState {
74 Unauthenticated,
76 Authenticated,
78}
79
80#[derive(Clone, Copy, Debug, PartialEq, Eq)]
85pub struct NegotiatedParticipantCapability {
86 protocol_version: ProtocolVersion,
87 max_frame_bytes: ValidatedFrameLimit,
88}
89
90impl NegotiatedParticipantCapability {
91 #[must_use]
93 pub const fn v1(max_frame_bytes: ValidatedFrameLimit) -> Self {
94 Self {
95 protocol_version: ProtocolVersion::V1,
96 max_frame_bytes,
97 }
98 }
99
100 #[must_use]
102 pub const fn protocol_version(self) -> ProtocolVersion {
103 self.protocol_version
104 }
105
106 #[must_use]
108 pub const fn max_frame_bytes(self) -> ValidatedFrameLimit {
109 self.max_frame_bytes
110 }
111}
112
113#[derive(Clone, Copy, Debug, PartialEq, Eq)]
115pub enum ParticipantCapabilityState {
116 Missing,
118 Negotiated(NegotiatedParticipantCapability),
120}
121
122#[derive(Clone, Copy, Debug, PartialEq, Eq)]
124pub struct InboundGateContext {
125 pub receiver: ReceiverDirection,
127 pub authentication: AuthenticationState,
129 pub participant_capability: ParticipantCapabilityState,
131}
132
133#[derive(Clone, Debug, PartialEq, Eq)]
135pub enum ParticipantFrame {
136 ClientRequest(ClientRequest),
138 ServerValue(ServerValue),
140 ServerPush(ServerPush),
142}
143
144#[derive(Clone, Debug, PartialEq, Eq)]
150pub enum InboundGateError {
151 NotParticipantFrame {
153 frame_type: u8,
155 },
156 ParticipantRejected(ParticipantTransportRejected),
158}
159
160#[derive(Clone, Copy, Debug, PartialEq, Eq)]
162pub enum CodecError {
163 NotParticipantFrame {
165 frame_type: u8,
167 },
168 Decode {
170 class: DecodeClass,
172 },
173 UnsupportedVersion {
175 presented: ProtocolVersion,
177 supported: ProtocolVersion,
179 },
180 OutputTooSmall {
182 required: usize,
184 available: usize,
186 },
187 LengthOverflow,
189 InvalidValue,
191 InvalidFrameLimit {
193 max_frame_bytes: u64,
195 },
196}
197
198#[must_use]
200pub fn complete_frame_bytes(payload_length: u32) -> u64 {
201 10 + u64::from(payload_length)
202}
203
204pub fn gate_inbound(
224 input: &[u8],
225 context: InboundGateContext,
226) -> Result<ParticipantFrame, InboundGateError> {
227 if let Some(frame_type) = input.first().copied() {
228 if frame_type != PARTICIPANT_FRAME_TYPE {
229 return Err(InboundGateError::NotParticipantFrame { frame_type });
230 }
231 }
232
233 let max_frame_bytes = match context.participant_capability {
234 ParticipantCapabilityState::Missing => PRECAP_PARTICIPANT_FRAME_MAX,
235 ParticipantCapabilityState::Negotiated(capability) => capability.max_frame_bytes().get(),
236 };
237
238 if let Some(complete_frame_bytes) = declared_complete_frame_bytes(input) {
239 if complete_frame_bytes > max_frame_bytes {
240 return Err(gate_rejection(TransportRejectionReason::FrameTooLarge {
241 complete_frame_bytes,
242 max_frame_bytes,
243 }));
244 }
245 }
246
247 let frame = decode(input, context.receiver).map_err(codec_gate_error)?;
248 if matches!(
249 (&frame, context.receiver),
250 (
251 ParticipantFrame::ServerValue(ServerValue::ParticipantTransportRejected(_)),
252 ReceiverDirection::Client
253 )
254 ) {
255 return Ok(frame);
256 }
257
258 if context.authentication == AuthenticationState::Unauthenticated {
259 return Err(gate_rejection(
260 TransportRejectionReason::AuthenticationFailed,
261 ));
262 }
263 if context.participant_capability == ParticipantCapabilityState::Missing {
264 return Err(gate_rejection(
265 TransportRejectionReason::ParticipantCapabilityRequired,
266 ));
267 }
268
269 Ok(frame)
270}
271
272pub fn encoded_len(frame: &ParticipantFrame) -> Result<usize, CodecError> {
279 let mut size = SizeSink::default();
280 encode_body(frame, &mut size)?;
281 let payload = PARTICIPANT_PREFIX_LEN
282 .checked_add(size.len)
283 .ok_or(CodecError::LengthOverflow)?;
284 let _: u32 = payload.try_into().map_err(|_| CodecError::LengthOverflow)?;
285 GENERIC_HEADER_LEN
286 .checked_add(payload)
287 .ok_or(CodecError::LengthOverflow)
288}
289
290pub fn encode(frame: &ParticipantFrame, output: &mut [u8]) -> Result<usize, CodecError> {
301 let required = encoded_len(frame)?;
302 if output.len() < required {
303 return Err(CodecError::OutputTooSmall {
304 required,
305 available: output.len(),
306 });
307 }
308
309 let payload_len = required
310 .checked_sub(GENERIC_HEADER_LEN)
311 .ok_or(CodecError::LengthOverflow)?;
312 let payload_len: u32 = payload_len
313 .try_into()
314 .map_err(|_| CodecError::LengthOverflow)?;
315 let discriminant = frame_discriminant(frame);
316
317 let mut writer = Writer::new(output);
318 writer.put_u8(PARTICIPANT_FRAME_TYPE)?;
319 writer.put_u8(0)?;
320 writer.put_u32(0)?;
321 writer.put_u32(payload_len)?;
322 writer.put_u16(ProtocolVersion::V1.major)?;
323 writer.put_u16(ProtocolVersion::V1.minor)?;
324 writer.put_u16(discriminant)?;
325 encode_body(frame, &mut writer)?;
326 Ok(required)
327}
328
329pub fn decode(input: &[u8], receiver: ReceiverDirection) -> Result<ParticipantFrame, CodecError> {
341 if let Some(frame_type) = input.first().copied() {
342 if frame_type != PARTICIPANT_FRAME_TYPE {
343 return Err(CodecError::NotParticipantFrame { frame_type });
344 }
345 }
346 if input.len() < GENERIC_HEADER_LEN {
347 return Err(decode_error(DecodeClass::Framing));
348 }
349
350 let mut header = Reader::new(input);
351 let _frame_type = header.take_u8()?;
352 let flags = header.take_u8()?;
353 let stream_id = header.take_u32()?;
354 let payload_len = header.take_u32()?;
355 if flags != 0 || stream_id != 0 || payload_len < 6 {
356 return Err(decode_error(DecodeClass::Framing));
357 }
358
359 let complete: usize = complete_frame_bytes(payload_len)
360 .try_into()
361 .map_err(|_| decode_error(DecodeClass::Framing))?;
362 if input.len() < complete {
363 return Err(decode_error(DecodeClass::MissingRequiredField));
364 }
365 if input.len() > complete {
366 return Err(decode_error(DecodeClass::CanonicalEncoding));
367 }
368
369 let payload = input
370 .get(GENERIC_HEADER_LEN..complete)
371 .ok_or_else(|| decode_error(DecodeClass::MissingRequiredField))?;
372 let mut prefix = Reader::new(payload);
373 let version = ProtocolVersion::new(prefix.take_u16()?, prefix.take_u16()?);
374 if version != ProtocolVersion::V1 {
375 return Err(CodecError::UnsupportedVersion {
376 presented: version,
377 supported: ProtocolVersion::V1,
378 });
379 }
380 let discriminant = prefix.take_u16()?;
381 let body = prefix.remaining_bytes();
382
383 match receiver {
384 ReceiverDirection::Server => {
385 let tag = ClientDiscriminant::try_from(discriminant)
386 .map_err(|_| decode_error(DecodeClass::UnknownDiscriminant))?;
387 decode_client_request(tag, body).map(ParticipantFrame::ClientRequest)
388 }
389 ReceiverDirection::Client => {
390 if let Ok(tag) = PushDiscriminant::try_from(discriminant) {
391 return decode_server_push(tag, body).map(ParticipantFrame::ServerPush);
392 }
393 if let Ok(tag) = ServerDiscriminant::try_from(discriminant) {
394 let (value, _) = super::server_codec::decode_server_value_body(tag, version, body)?;
395 return Ok(ParticipantFrame::ServerValue(value));
396 }
397 Err(decode_error(DecodeClass::UnknownDiscriminant))
398 }
399 }
400}
401
402fn declared_complete_frame_bytes(input: &[u8]) -> Option<u64> {
403 let payload_length = input.get(6..GENERIC_HEADER_LEN)?;
404 let payload_length = <[u8; 4]>::try_from(payload_length).ok()?;
405 Some(complete_frame_bytes(u32::from_be_bytes(payload_length)))
406}
407
408const fn transport_rejection(reason: TransportRejectionReason) -> ParticipantTransportRejected {
409 ParticipantTransportRejected { reason }
410}
411
412const fn gate_rejection(reason: TransportRejectionReason) -> InboundGateError {
413 InboundGateError::ParticipantRejected(transport_rejection(reason))
414}
415
416const fn codec_gate_error(error: CodecError) -> InboundGateError {
417 match error {
418 CodecError::NotParticipantFrame { frame_type } => {
419 InboundGateError::NotParticipantFrame { frame_type }
420 }
421 CodecError::Decode { class } => gate_rejection(TransportRejectionReason::DecodeFailed {
422 decode_class: class,
423 }),
424 CodecError::UnsupportedVersion {
425 presented,
426 supported,
427 } => gate_rejection(TransportRejectionReason::UnsupportedVersion {
428 presented_version: presented,
429 supported_version: supported,
430 }),
431 CodecError::OutputTooSmall { .. }
432 | CodecError::LengthOverflow
433 | CodecError::InvalidValue
434 | CodecError::InvalidFrameLimit { .. } => {
435 gate_rejection(TransportRejectionReason::DecodeFailed {
436 decode_class: DecodeClass::InvalidField,
437 })
438 }
439 }
440}
441
442const fn frame_discriminant(frame: &ParticipantFrame) -> u16 {
443 match frame {
444 ParticipantFrame::ClientRequest(value) => value.discriminant().wire_value(),
445 ParticipantFrame::ServerValue(value) => value.discriminant().wire_value(),
446 ParticipantFrame::ServerPush(value) => value.discriminant().wire_value(),
447 }
448}
449
450fn encode_body<S: Sink>(frame: &ParticipantFrame, sink: &mut S) -> Result<(), CodecError> {
451 match frame {
452 ParticipantFrame::ClientRequest(value) => encode_client_request(value, sink),
453 ParticipantFrame::ServerPush(value) => encode_server_push(value, sink),
454 ParticipantFrame::ServerValue(value) => {
455 let (_, body) =
456 super::server_codec::encode_server_value_body(value, ProtocolVersion::V1)?;
457 sink.put(&body)
458 }
459 }
460}
461
462fn encode_client_request<S: Sink>(value: &ClientRequest, sink: &mut S) -> Result<(), CodecError> {
463 match value {
464 ClientRequest::Enrollment(value) => {
465 sink.put_u64(value.conversation_id)?;
466 sink.put_fixed(value.enrollment_token.as_bytes())
467 }
468 ClientRequest::CredentialAttach(value) => {
469 sink.put_u64(value.conversation_id)?;
470 sink.put_u64(value.participant_id)?;
471 put_generation(sink, value.capability_generation)?;
472 sink.put_fixed(value.attach_secret.as_bytes())?;
473 sink.put_fixed(value.attach_attempt_token.as_bytes())?;
474 put_option_u64(sink, value.accept_marker_delivery_seq)
475 }
476 ClientRequest::Detach(value) => {
477 sink.put_u64(value.conversation_id)?;
478 sink.put_u64(value.participant_id)?;
479 put_generation(sink, value.capability_generation)?;
480 sink.put_fixed(value.detach_attempt_token.as_bytes())
481 }
482 ClientRequest::ParticipantAck(value) => {
483 sink.put_u64(value.conversation_id)?;
484 sink.put_u64(value.participant_id)?;
485 put_generation(sink, value.capability_generation)?;
486 sink.put_u64(value.through_seq)
487 }
488 ClientRequest::Leave(value) => {
489 sink.put_u64(value.conversation_id)?;
490 sink.put_u64(value.participant_id)?;
491 put_generation(sink, value.capability_generation)?;
492 sink.put_fixed(value.attach_secret.as_bytes())?;
493 sink.put_fixed(value.leave_attempt_token.as_bytes())
494 }
495 ClientRequest::MarkerAck(value) => {
496 sink.put_u64(value.conversation_id)?;
497 sink.put_u64(value.participant_id)?;
498 put_generation(sink, value.capability_generation)?;
499 sink.put_u64(value.marker_delivery_seq)
500 }
501 ClientRequest::RecordAdmission(value) => {
502 sink.put_u64(value.conversation_id)?;
503 sink.put_u64(value.participant_id)?;
504 put_generation(sink, value.capability_generation)?;
505 sink.put_fixed(value.record_admission_attempt_token.as_bytes())?;
506 sink.put_bytes(&value.payload)
507 }
508 ClientRequest::SettlementQuery(value) => {
509 sink.put_u64(value.conversation_id)?;
510 sink.put_u64(value.participant_id)?;
511 put_generation(sink, value.capability_generation)?;
512 sink.put_fixed(value.record_admission_attempt_token.as_bytes())?;
513 sink.put_fixed(&value.payload_fingerprint)
514 }
515 ClientRequest::ObserverRecovery(value) => {
516 let count: u64 = value
517 .observer_refusals
518 .len()
519 .try_into()
520 .map_err(|_| CodecError::LengthOverflow)?;
521 sink.put_u64(count)?;
522 for refusal in &value.observer_refusals {
523 sink.put_u64(refusal.conversation_id)?;
524 sink.put_u64(refusal.refused_epoch)?;
525 }
526 Ok(())
527 }
528 }
529}
530
531fn decode_client_request(
532 tag: ClientDiscriminant,
533 body: &[u8],
534) -> Result<ClientRequest, CodecError> {
535 let mut reader = Reader::new(body);
536 let value = match tag {
537 ClientDiscriminant::EnrollmentRequest => ClientRequest::Enrollment(EnrollmentRequest {
538 conversation_id: reader.take_u64()?,
539 enrollment_token: EnrollmentToken::new(reader.take_fixed()?),
540 }),
541 ClientDiscriminant::CredentialAttachRequest => {
542 ClientRequest::CredentialAttach(CredentialAttachRequest {
543 conversation_id: reader.take_u64()?,
544 participant_id: reader.take_u64()?,
545 capability_generation: reader.take_generation()?,
546 attach_secret: AttachSecret::new(reader.take_fixed()?),
547 attach_attempt_token: AttachAttemptToken::new(reader.take_fixed()?),
548 accept_marker_delivery_seq: reader.take_option_u64()?,
549 })
550 }
551 ClientDiscriminant::DetachRequest => ClientRequest::Detach(DetachRequest {
552 conversation_id: reader.take_u64()?,
553 participant_id: reader.take_u64()?,
554 capability_generation: reader.take_generation()?,
555 detach_attempt_token: DetachAttemptToken::new(reader.take_fixed()?),
556 }),
557 ClientDiscriminant::ParticipantAck => ClientRequest::ParticipantAck(ParticipantAck {
558 conversation_id: reader.take_u64()?,
559 participant_id: reader.take_u64()?,
560 capability_generation: reader.take_generation()?,
561 through_seq: reader.take_u64()?,
562 }),
563 ClientDiscriminant::LeaveRequest => ClientRequest::Leave(LeaveRequest {
564 conversation_id: reader.take_u64()?,
565 participant_id: reader.take_u64()?,
566 capability_generation: reader.take_generation()?,
567 attach_secret: AttachSecret::new(reader.take_fixed()?),
568 leave_attempt_token: LeaveAttemptToken::new(reader.take_fixed()?),
569 }),
570 ClientDiscriminant::MarkerAck => ClientRequest::MarkerAck(MarkerAck {
571 conversation_id: reader.take_u64()?,
572 participant_id: reader.take_u64()?,
573 capability_generation: reader.take_generation()?,
574 marker_delivery_seq: reader.take_u64()?,
575 }),
576 ClientDiscriminant::RecordAdmission => ClientRequest::RecordAdmission(RecordAdmission {
577 conversation_id: reader.take_u64()?,
578 participant_id: reader.take_u64()?,
579 capability_generation: reader.take_generation()?,
580 record_admission_attempt_token: RecordAdmissionAttemptToken::new(reader.take_fixed()?),
581 payload: reader.take_bytes()?,
582 }),
583 ClientDiscriminant::SettlementQuery => ClientRequest::SettlementQuery(SettlementQuery {
584 conversation_id: reader.take_u64()?,
585 participant_id: reader.take_u64()?,
586 capability_generation: reader.take_generation()?,
587 record_admission_attempt_token: RecordAdmissionAttemptToken::new(reader.take_fixed()?),
588 payload_fingerprint: reader.take_fixed()?,
589 }),
590 ClientDiscriminant::ObserverRecoveryHandshake => {
591 let count = reader.take_u64()?;
592 reader.require_fixed_list(count, 16)?;
593 let mut observer_refusals = Vec::new();
594 for _ in 0..count {
595 observer_refusals.push(ObserverRefusal {
596 conversation_id: reader.take_u64()?,
597 refused_epoch: reader.take_u64()?,
598 });
599 }
600 ClientRequest::ObserverRecovery(ObserverRecoveryHandshake { observer_refusals })
601 }
602 };
603 reader.finish()?;
604 Ok(value)
605}
606
607fn encode_server_push<S: Sink>(value: &ServerPush, sink: &mut S) -> Result<(), CodecError> {
608 match value {
609 ServerPush::ObserverProgressed {
610 conversation_id,
611 refused_epoch,
612 observer_progress,
613 } => {
614 sink.put_u64(*conversation_id)?;
615 sink.put_u64(*refused_epoch)?;
616 sink.put_u64(*observer_progress)
617 }
618 ServerPush::ParticipantDelivery(value) => encode_participant_delivery(value, sink),
619 ServerPush::MarkerSettled {
620 conversation_id,
621 refused_epoch,
622 } => {
623 sink.put_u64(*conversation_id)?;
624 sink.put_u64(*refused_epoch)
625 }
626 }
627}
628
629fn encode_participant_delivery<S: Sink>(
630 value: &ParticipantDelivery,
631 sink: &mut S,
632) -> Result<(), CodecError> {
633 sink.put_u64(value.conversation_id)?;
634 sink.put_u64(value.delivery_seq)?;
635 sink.put_u16(value.record.record_kind().wire_value())?;
636 match &value.record {
637 ParticipantRecord::OrdinaryRecord {
638 sender_participant_id,
639 payload,
640 } => {
641 sink.put_u64(*sender_participant_id)?;
642 sink.put_bytes(payload)
643 }
644 ParticipantRecord::Attached {
645 affected_participant_id,
646 binding_epoch,
647 } => {
648 sink.put_u64(*affected_participant_id)?;
649 put_binding_epoch(sink, *binding_epoch)
650 }
651 ParticipantRecord::Detached {
652 affected_participant_id,
653 binding_epoch,
654 cause,
655 } => {
656 sink.put_u64(*affected_participant_id)?;
657 put_binding_epoch(sink, *binding_epoch)?;
658 sink.put_u16(cause.close_cause().tag().wire_value())
659 }
660 ParticipantRecord::Died {
661 affected_participant_id,
662 binding_epoch,
663 cause,
664 } => {
665 sink.put_u64(*affected_participant_id)?;
666 put_binding_epoch(sink, *binding_epoch)?;
667 sink.put_u16(cause.close_cause().tag().wire_value())?;
668 if let DiedCause::UncleanServerRestart {
669 prior_server_incarnation,
670 } = cause
671 {
672 sink.put_u64(*prior_server_incarnation)?;
673 }
674 Ok(())
675 }
676 ParticipantRecord::Left {
677 affected_participant_id,
678 ended_binding_epoch,
679 } => {
680 sink.put_u64(*affected_participant_id)?;
681 put_option_binding_epoch(sink, *ended_binding_epoch)
682 }
683 ParticipantRecord::HistoryCompacted {
684 affected_participant_id,
685 abandoned_after,
686 abandoned_through,
687 physical_floor_at_decision,
688 } => {
689 sink.put_u64(*affected_participant_id)?;
690 sink.put_u64(*abandoned_after)?;
691 sink.put_u64(*abandoned_through)?;
692 sink.put_u64(*physical_floor_at_decision)
693 }
694 }
695}
696
697fn decode_server_push(tag: PushDiscriminant, body: &[u8]) -> Result<ServerPush, CodecError> {
698 let mut reader = Reader::new(body);
699 let value = match tag {
700 PushDiscriminant::ObserverProgressed => ServerPush::ObserverProgressed {
701 conversation_id: reader.take_u64()?,
702 refused_epoch: reader.take_u64()?,
703 observer_progress: reader.take_u64()?,
704 },
705 PushDiscriminant::ParticipantDelivery => {
706 let conversation_id = reader.take_u64()?;
707 let delivery_seq = reader.take_u64()?;
708 let kind = RecordKind::try_from(reader.take_u16()?)
709 .map_err(|_| decode_error(DecodeClass::InvalidField))?;
710 let record = decode_participant_record(kind, &mut reader)?;
711 ServerPush::ParticipantDelivery(ParticipantDelivery {
712 conversation_id,
713 delivery_seq,
714 record,
715 })
716 }
717 PushDiscriminant::MarkerSettled => ServerPush::MarkerSettled {
718 conversation_id: reader.take_u64()?,
719 refused_epoch: reader.take_u64()?,
720 },
721 };
722 reader.finish()?;
723 Ok(value)
724}
725
726fn decode_participant_record(
727 kind: RecordKind,
728 reader: &mut Reader<'_>,
729) -> Result<ParticipantRecord, CodecError> {
730 match kind {
731 RecordKind::OrdinaryRecord => Ok(ParticipantRecord::OrdinaryRecord {
732 sender_participant_id: reader.take_u64()?,
733 payload: reader.take_bytes()?,
734 }),
735 RecordKind::Attached => Ok(ParticipantRecord::Attached {
736 affected_participant_id: reader.take_u64()?,
737 binding_epoch: reader.take_binding_epoch()?,
738 }),
739 RecordKind::Detached => {
740 let affected_participant_id = reader.take_u64()?;
741 let binding_epoch = reader.take_binding_epoch()?;
742 let tag = CloseCauseTag::try_from(reader.take_u16()?)
743 .map_err(|_| decode_error(DecodeClass::InvalidField))?;
744 let cause = match tag {
745 CloseCauseTag::CleanDeregister => DetachedCause::CleanDeregister,
746 CloseCauseTag::Superseded => DetachedCause::Superseded,
747 CloseCauseTag::ServerShutdown => DetachedCause::ServerShutdown,
748 _ => return Err(decode_error(DecodeClass::InvalidField)),
749 };
750 Ok(ParticipantRecord::Detached {
751 affected_participant_id,
752 binding_epoch,
753 cause,
754 })
755 }
756 RecordKind::Died => {
757 let affected_participant_id = reader.take_u64()?;
758 let binding_epoch = reader.take_binding_epoch()?;
759 let tag = CloseCauseTag::try_from(reader.take_u16()?)
760 .map_err(|_| decode_error(DecodeClass::InvalidField))?;
761 let cause = match tag {
762 CloseCauseTag::ConnectionLost => DiedCause::ConnectionLost,
763 CloseCauseTag::ProcessKilled => DiedCause::ProcessKilled,
764 CloseCauseTag::ProtocolError => DiedCause::ProtocolError,
765 CloseCauseTag::UncleanServerRestart => DiedCause::UncleanServerRestart {
766 prior_server_incarnation: reader.take_u64()?,
767 },
768 _ => return Err(decode_error(DecodeClass::InvalidField)),
769 };
770 Ok(ParticipantRecord::Died {
771 affected_participant_id,
772 binding_epoch,
773 cause,
774 })
775 }
776 RecordKind::Left => Ok(ParticipantRecord::Left {
777 affected_participant_id: reader.take_u64()?,
778 ended_binding_epoch: reader.take_option_binding_epoch()?,
779 }),
780 RecordKind::HistoryCompacted => Ok(ParticipantRecord::HistoryCompacted {
781 affected_participant_id: reader.take_u64()?,
782 abandoned_after: reader.take_u64()?,
783 abandoned_through: reader.take_u64()?,
784 physical_floor_at_decision: reader.take_u64()?,
785 }),
786 }
787}
788
789fn put_generation<S: Sink>(sink: &mut S, generation: Generation) -> Result<(), CodecError> {
790 sink.put_u64(generation.get())
791}
792
793fn put_connection_incarnation<S: Sink>(
794 sink: &mut S,
795 value: ConnectionIncarnation,
796) -> Result<(), CodecError> {
797 sink.put_u64(value.server_incarnation)?;
798 sink.put_u64(value.connection_ordinal)
799}
800
801fn put_binding_epoch<S: Sink>(sink: &mut S, value: BindingEpoch) -> Result<(), CodecError> {
802 put_connection_incarnation(sink, value.connection_incarnation)?;
803 put_generation(sink, value.capability_generation)
804}
805
806fn put_option_u64<S: Sink>(sink: &mut S, value: Option<u64>) -> Result<(), CodecError> {
807 match value {
808 None => sink.put_u8(0),
809 Some(value) => {
810 sink.put_u8(1)?;
811 sink.put_u64(value)
812 }
813 }
814}
815
816fn put_option_binding_epoch<S: Sink>(
817 sink: &mut S,
818 value: Option<BindingEpoch>,
819) -> Result<(), CodecError> {
820 match value {
821 None => sink.put_u8(0),
822 Some(value) => {
823 sink.put_u8(1)?;
824 put_binding_epoch(sink, value)
825 }
826 }
827}
828
829const fn decode_error(class: DecodeClass) -> CodecError {
830 CodecError::Decode { class }
831}
832
833trait Sink {
834 fn put(&mut self, bytes: &[u8]) -> Result<(), CodecError>;
835
836 fn put_u8(&mut self, value: u8) -> Result<(), CodecError> {
837 self.put(&[value])
838 }
839
840 fn put_u16(&mut self, value: u16) -> Result<(), CodecError> {
841 self.put(&value.to_be_bytes())
842 }
843
844 fn put_u32(&mut self, value: u32) -> Result<(), CodecError> {
845 self.put(&value.to_be_bytes())
846 }
847
848 fn put_u64(&mut self, value: u64) -> Result<(), CodecError> {
849 self.put(&value.to_be_bytes())
850 }
851
852 fn put_fixed<const N: usize>(&mut self, value: &[u8; N]) -> Result<(), CodecError> {
853 self.put(value)
854 }
855
856 fn put_bytes(&mut self, value: &[u8]) -> Result<(), CodecError> {
857 let length: u32 = value
858 .len()
859 .try_into()
860 .map_err(|_| CodecError::LengthOverflow)?;
861 self.put_u32(length)?;
862 self.put(value)
863 }
864}
865
866#[derive(Default)]
867struct SizeSink {
868 len: usize,
869}
870
871impl Sink for SizeSink {
872 fn put(&mut self, bytes: &[u8]) -> Result<(), CodecError> {
873 self.len = self
874 .len
875 .checked_add(bytes.len())
876 .ok_or(CodecError::LengthOverflow)?;
877 Ok(())
878 }
879}
880
881struct Writer<'a> {
882 output: &'a mut [u8],
883 position: usize,
884}
885
886impl<'a> Writer<'a> {
887 const fn new(output: &'a mut [u8]) -> Self {
888 Self {
889 output,
890 position: 0,
891 }
892 }
893}
894
895impl Sink for Writer<'_> {
896 fn put(&mut self, bytes: &[u8]) -> Result<(), CodecError> {
897 let end = self
898 .position
899 .checked_add(bytes.len())
900 .ok_or(CodecError::LengthOverflow)?;
901 let available = self.output.len();
902 let Some(destination) = self.output.get_mut(self.position..end) else {
903 return Err(CodecError::OutputTooSmall {
904 required: end,
905 available,
906 });
907 };
908 destination.copy_from_slice(bytes);
909 self.position = end;
910 Ok(())
911 }
912}
913
914struct Reader<'a> {
915 input: &'a [u8],
916 position: usize,
917 invalid_field: bool,
918}
919
920impl<'a> Reader<'a> {
921 const fn new(input: &'a [u8]) -> Self {
922 Self {
923 input,
924 position: 0,
925 invalid_field: false,
926 }
927 }
928
929 const fn remaining(&self) -> usize {
930 self.input.len().saturating_sub(self.position)
931 }
932
933 fn remaining_bytes(&self) -> &'a [u8] {
934 match self.input.get(self.position..) {
935 Some(bytes) => bytes,
936 None => &[],
937 }
938 }
939
940 fn take(&mut self, length: usize) -> Result<&'a [u8], CodecError> {
941 let end = self
942 .position
943 .checked_add(length)
944 .ok_or_else(|| decode_error(DecodeClass::MissingRequiredField))?;
945 let Some(bytes) = self.input.get(self.position..end) else {
946 return Err(decode_error(DecodeClass::MissingRequiredField));
947 };
948 self.position = end;
949 Ok(bytes)
950 }
951
952 fn take_fixed<const N: usize>(&mut self) -> Result<[u8; N], CodecError> {
953 let mut output = [0; N];
954 output.copy_from_slice(self.take(N)?);
955 Ok(output)
956 }
957
958 fn take_u8(&mut self) -> Result<u8, CodecError> {
959 Ok(u8::from_be_bytes(self.take_fixed()?))
960 }
961
962 fn take_u16(&mut self) -> Result<u16, CodecError> {
963 Ok(u16::from_be_bytes(self.take_fixed()?))
964 }
965
966 fn take_u32(&mut self) -> Result<u32, CodecError> {
967 Ok(u32::from_be_bytes(self.take_fixed()?))
968 }
969
970 fn take_u64(&mut self) -> Result<u64, CodecError> {
971 Ok(u64::from_be_bytes(self.take_fixed()?))
972 }
973
974 fn take_generation(&mut self) -> Result<Generation, CodecError> {
975 let raw = self.take_u64()?;
976 if let Some(value) = Generation::new(raw) {
977 return Ok(value);
978 }
979 self.invalid_field = true;
980 Generation::new(1).ok_or(decode_error(DecodeClass::InvalidField))
981 }
982
983 fn take_binding_epoch(&mut self) -> Result<BindingEpoch, CodecError> {
984 Ok(BindingEpoch::new(
985 ConnectionIncarnation::new(self.take_u64()?, self.take_u64()?),
986 self.take_generation()?,
987 ))
988 }
989
990 fn take_option_u64(&mut self) -> Result<Option<u64>, CodecError> {
991 match self.take_u8()? {
992 0 => Ok(None),
993 1 => self.take_u64().map(Some),
994 _ => Err(decode_error(DecodeClass::InvalidField)),
995 }
996 }
997
998 fn take_option_binding_epoch(&mut self) -> Result<Option<BindingEpoch>, CodecError> {
999 match self.take_u8()? {
1000 0 => Ok(None),
1001 1 => self.take_binding_epoch().map(Some),
1002 _ => Err(decode_error(DecodeClass::InvalidField)),
1003 }
1004 }
1005
1006 fn take_bytes(&mut self) -> Result<Vec<u8>, CodecError> {
1007 let length: usize = self
1008 .take_u32()?
1009 .try_into()
1010 .map_err(|_| decode_error(DecodeClass::MissingRequiredField))?;
1011 Ok(self.take(length)?.to_vec())
1012 }
1013
1014 fn require_fixed_list(&self, count: u64, width: usize) -> Result<(), CodecError> {
1015 let width =
1016 u128::try_from(width).map_err(|_| decode_error(DecodeClass::MissingRequiredField))?;
1017 let remaining = u128::try_from(self.remaining())
1018 .map_err(|_| decode_error(DecodeClass::MissingRequiredField))?;
1019 let required = u128::from(count)
1020 .checked_mul(width)
1021 .ok_or_else(|| decode_error(DecodeClass::MissingRequiredField))?;
1022 if required > remaining {
1023 return Err(decode_error(DecodeClass::MissingRequiredField));
1024 }
1025 Ok(())
1026 }
1027
1028 const fn finish(self) -> Result<(), CodecError> {
1029 if self.position != self.input.len() {
1030 return Err(decode_error(DecodeClass::CanonicalEncoding));
1031 }
1032 if self.invalid_field {
1033 return Err(decode_error(DecodeClass::InvalidField));
1034 }
1035 Ok(())
1036 }
1037}