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, 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::ObserverRecovery(value) => {
509 let count: u64 = value
510 .observer_refusals
511 .len()
512 .try_into()
513 .map_err(|_| CodecError::LengthOverflow)?;
514 sink.put_u64(count)?;
515 for refusal in &value.observer_refusals {
516 sink.put_u64(refusal.conversation_id)?;
517 sink.put_u64(refusal.refused_epoch)?;
518 }
519 Ok(())
520 }
521 }
522}
523
524fn decode_client_request(
525 tag: ClientDiscriminant,
526 body: &[u8],
527) -> Result<ClientRequest, CodecError> {
528 let mut reader = Reader::new(body);
529 let value = match tag {
530 ClientDiscriminant::EnrollmentRequest => ClientRequest::Enrollment(EnrollmentRequest {
531 conversation_id: reader.take_u64()?,
532 enrollment_token: EnrollmentToken::new(reader.take_fixed()?),
533 }),
534 ClientDiscriminant::CredentialAttachRequest => {
535 ClientRequest::CredentialAttach(CredentialAttachRequest {
536 conversation_id: reader.take_u64()?,
537 participant_id: reader.take_u64()?,
538 capability_generation: reader.take_generation()?,
539 attach_secret: AttachSecret::new(reader.take_fixed()?),
540 attach_attempt_token: AttachAttemptToken::new(reader.take_fixed()?),
541 accept_marker_delivery_seq: reader.take_option_u64()?,
542 })
543 }
544 ClientDiscriminant::DetachRequest => ClientRequest::Detach(DetachRequest {
545 conversation_id: reader.take_u64()?,
546 participant_id: reader.take_u64()?,
547 capability_generation: reader.take_generation()?,
548 detach_attempt_token: DetachAttemptToken::new(reader.take_fixed()?),
549 }),
550 ClientDiscriminant::ParticipantAck => ClientRequest::ParticipantAck(ParticipantAck {
551 conversation_id: reader.take_u64()?,
552 participant_id: reader.take_u64()?,
553 capability_generation: reader.take_generation()?,
554 through_seq: reader.take_u64()?,
555 }),
556 ClientDiscriminant::LeaveRequest => ClientRequest::Leave(LeaveRequest {
557 conversation_id: reader.take_u64()?,
558 participant_id: reader.take_u64()?,
559 capability_generation: reader.take_generation()?,
560 attach_secret: AttachSecret::new(reader.take_fixed()?),
561 leave_attempt_token: LeaveAttemptToken::new(reader.take_fixed()?),
562 }),
563 ClientDiscriminant::MarkerAck => ClientRequest::MarkerAck(MarkerAck {
564 conversation_id: reader.take_u64()?,
565 participant_id: reader.take_u64()?,
566 capability_generation: reader.take_generation()?,
567 marker_delivery_seq: reader.take_u64()?,
568 }),
569 ClientDiscriminant::RecordAdmission => ClientRequest::RecordAdmission(RecordAdmission {
570 conversation_id: reader.take_u64()?,
571 participant_id: reader.take_u64()?,
572 capability_generation: reader.take_generation()?,
573 record_admission_attempt_token: RecordAdmissionAttemptToken::new(reader.take_fixed()?),
574 payload: reader.take_bytes()?,
575 }),
576 ClientDiscriminant::ObserverRecoveryHandshake => {
577 let count = reader.take_u64()?;
578 reader.require_fixed_list(count, 16)?;
579 let mut observer_refusals = Vec::new();
580 for _ in 0..count {
581 observer_refusals.push(ObserverRefusal {
582 conversation_id: reader.take_u64()?,
583 refused_epoch: reader.take_u64()?,
584 });
585 }
586 ClientRequest::ObserverRecovery(ObserverRecoveryHandshake { observer_refusals })
587 }
588 };
589 reader.finish()?;
590 Ok(value)
591}
592
593fn encode_server_push<S: Sink>(value: &ServerPush, sink: &mut S) -> Result<(), CodecError> {
594 match value {
595 ServerPush::ObserverProgressed {
596 conversation_id,
597 refused_epoch,
598 observer_progress,
599 } => {
600 sink.put_u64(*conversation_id)?;
601 sink.put_u64(*refused_epoch)?;
602 sink.put_u64(*observer_progress)
603 }
604 ServerPush::ParticipantDelivery(value) => encode_participant_delivery(value, sink),
605 }
606}
607
608fn encode_participant_delivery<S: Sink>(
609 value: &ParticipantDelivery,
610 sink: &mut S,
611) -> Result<(), CodecError> {
612 sink.put_u64(value.conversation_id)?;
613 sink.put_u64(value.delivery_seq)?;
614 sink.put_u16(value.record.record_kind().wire_value())?;
615 match &value.record {
616 ParticipantRecord::OrdinaryRecord {
617 sender_participant_id,
618 payload,
619 } => {
620 sink.put_u64(*sender_participant_id)?;
621 sink.put_bytes(payload)
622 }
623 ParticipantRecord::Attached {
624 affected_participant_id,
625 binding_epoch,
626 } => {
627 sink.put_u64(*affected_participant_id)?;
628 put_binding_epoch(sink, *binding_epoch)
629 }
630 ParticipantRecord::Detached {
631 affected_participant_id,
632 binding_epoch,
633 cause,
634 } => {
635 sink.put_u64(*affected_participant_id)?;
636 put_binding_epoch(sink, *binding_epoch)?;
637 sink.put_u16(cause.close_cause().tag().wire_value())
638 }
639 ParticipantRecord::Died {
640 affected_participant_id,
641 binding_epoch,
642 cause,
643 } => {
644 sink.put_u64(*affected_participant_id)?;
645 put_binding_epoch(sink, *binding_epoch)?;
646 sink.put_u16(cause.close_cause().tag().wire_value())?;
647 if let DiedCause::UncleanServerRestart {
648 prior_server_incarnation,
649 } = cause
650 {
651 sink.put_u64(*prior_server_incarnation)?;
652 }
653 Ok(())
654 }
655 ParticipantRecord::Left {
656 affected_participant_id,
657 ended_binding_epoch,
658 } => {
659 sink.put_u64(*affected_participant_id)?;
660 put_option_binding_epoch(sink, *ended_binding_epoch)
661 }
662 ParticipantRecord::HistoryCompacted {
663 affected_participant_id,
664 abandoned_after,
665 abandoned_through,
666 physical_floor_at_decision,
667 } => {
668 sink.put_u64(*affected_participant_id)?;
669 sink.put_u64(*abandoned_after)?;
670 sink.put_u64(*abandoned_through)?;
671 sink.put_u64(*physical_floor_at_decision)
672 }
673 }
674}
675
676fn decode_server_push(tag: PushDiscriminant, body: &[u8]) -> Result<ServerPush, CodecError> {
677 let mut reader = Reader::new(body);
678 let value = match tag {
679 PushDiscriminant::ObserverProgressed => ServerPush::ObserverProgressed {
680 conversation_id: reader.take_u64()?,
681 refused_epoch: reader.take_u64()?,
682 observer_progress: reader.take_u64()?,
683 },
684 PushDiscriminant::ParticipantDelivery => {
685 let conversation_id = reader.take_u64()?;
686 let delivery_seq = reader.take_u64()?;
687 let kind = RecordKind::try_from(reader.take_u16()?)
688 .map_err(|_| decode_error(DecodeClass::InvalidField))?;
689 let record = decode_participant_record(kind, &mut reader)?;
690 ServerPush::ParticipantDelivery(ParticipantDelivery {
691 conversation_id,
692 delivery_seq,
693 record,
694 })
695 }
696 };
697 reader.finish()?;
698 Ok(value)
699}
700
701fn decode_participant_record(
702 kind: RecordKind,
703 reader: &mut Reader<'_>,
704) -> Result<ParticipantRecord, CodecError> {
705 match kind {
706 RecordKind::OrdinaryRecord => Ok(ParticipantRecord::OrdinaryRecord {
707 sender_participant_id: reader.take_u64()?,
708 payload: reader.take_bytes()?,
709 }),
710 RecordKind::Attached => Ok(ParticipantRecord::Attached {
711 affected_participant_id: reader.take_u64()?,
712 binding_epoch: reader.take_binding_epoch()?,
713 }),
714 RecordKind::Detached => {
715 let affected_participant_id = reader.take_u64()?;
716 let binding_epoch = reader.take_binding_epoch()?;
717 let tag = CloseCauseTag::try_from(reader.take_u16()?)
718 .map_err(|_| decode_error(DecodeClass::InvalidField))?;
719 let cause = match tag {
720 CloseCauseTag::CleanDeregister => DetachedCause::CleanDeregister,
721 CloseCauseTag::Superseded => DetachedCause::Superseded,
722 CloseCauseTag::ServerShutdown => DetachedCause::ServerShutdown,
723 _ => return Err(decode_error(DecodeClass::InvalidField)),
724 };
725 Ok(ParticipantRecord::Detached {
726 affected_participant_id,
727 binding_epoch,
728 cause,
729 })
730 }
731 RecordKind::Died => {
732 let affected_participant_id = reader.take_u64()?;
733 let binding_epoch = reader.take_binding_epoch()?;
734 let tag = CloseCauseTag::try_from(reader.take_u16()?)
735 .map_err(|_| decode_error(DecodeClass::InvalidField))?;
736 let cause = match tag {
737 CloseCauseTag::ConnectionLost => DiedCause::ConnectionLost,
738 CloseCauseTag::ProcessKilled => DiedCause::ProcessKilled,
739 CloseCauseTag::ProtocolError => DiedCause::ProtocolError,
740 CloseCauseTag::UncleanServerRestart => DiedCause::UncleanServerRestart {
741 prior_server_incarnation: reader.take_u64()?,
742 },
743 _ => return Err(decode_error(DecodeClass::InvalidField)),
744 };
745 Ok(ParticipantRecord::Died {
746 affected_participant_id,
747 binding_epoch,
748 cause,
749 })
750 }
751 RecordKind::Left => Ok(ParticipantRecord::Left {
752 affected_participant_id: reader.take_u64()?,
753 ended_binding_epoch: reader.take_option_binding_epoch()?,
754 }),
755 RecordKind::HistoryCompacted => Ok(ParticipantRecord::HistoryCompacted {
756 affected_participant_id: reader.take_u64()?,
757 abandoned_after: reader.take_u64()?,
758 abandoned_through: reader.take_u64()?,
759 physical_floor_at_decision: reader.take_u64()?,
760 }),
761 }
762}
763
764fn put_generation<S: Sink>(sink: &mut S, generation: Generation) -> Result<(), CodecError> {
765 sink.put_u64(generation.get())
766}
767
768fn put_connection_incarnation<S: Sink>(
769 sink: &mut S,
770 value: ConnectionIncarnation,
771) -> Result<(), CodecError> {
772 sink.put_u64(value.server_incarnation)?;
773 sink.put_u64(value.connection_ordinal)
774}
775
776fn put_binding_epoch<S: Sink>(sink: &mut S, value: BindingEpoch) -> Result<(), CodecError> {
777 put_connection_incarnation(sink, value.connection_incarnation)?;
778 put_generation(sink, value.capability_generation)
779}
780
781fn put_option_u64<S: Sink>(sink: &mut S, value: Option<u64>) -> Result<(), CodecError> {
782 match value {
783 None => sink.put_u8(0),
784 Some(value) => {
785 sink.put_u8(1)?;
786 sink.put_u64(value)
787 }
788 }
789}
790
791fn put_option_binding_epoch<S: Sink>(
792 sink: &mut S,
793 value: Option<BindingEpoch>,
794) -> Result<(), CodecError> {
795 match value {
796 None => sink.put_u8(0),
797 Some(value) => {
798 sink.put_u8(1)?;
799 put_binding_epoch(sink, value)
800 }
801 }
802}
803
804const fn decode_error(class: DecodeClass) -> CodecError {
805 CodecError::Decode { class }
806}
807
808trait Sink {
809 fn put(&mut self, bytes: &[u8]) -> Result<(), CodecError>;
810
811 fn put_u8(&mut self, value: u8) -> Result<(), CodecError> {
812 self.put(&[value])
813 }
814
815 fn put_u16(&mut self, value: u16) -> Result<(), CodecError> {
816 self.put(&value.to_be_bytes())
817 }
818
819 fn put_u32(&mut self, value: u32) -> Result<(), CodecError> {
820 self.put(&value.to_be_bytes())
821 }
822
823 fn put_u64(&mut self, value: u64) -> Result<(), CodecError> {
824 self.put(&value.to_be_bytes())
825 }
826
827 fn put_fixed<const N: usize>(&mut self, value: &[u8; N]) -> Result<(), CodecError> {
828 self.put(value)
829 }
830
831 fn put_bytes(&mut self, value: &[u8]) -> Result<(), CodecError> {
832 let length: u32 = value
833 .len()
834 .try_into()
835 .map_err(|_| CodecError::LengthOverflow)?;
836 self.put_u32(length)?;
837 self.put(value)
838 }
839}
840
841#[derive(Default)]
842struct SizeSink {
843 len: usize,
844}
845
846impl Sink for SizeSink {
847 fn put(&mut self, bytes: &[u8]) -> Result<(), CodecError> {
848 self.len = self
849 .len
850 .checked_add(bytes.len())
851 .ok_or(CodecError::LengthOverflow)?;
852 Ok(())
853 }
854}
855
856struct Writer<'a> {
857 output: &'a mut [u8],
858 position: usize,
859}
860
861impl<'a> Writer<'a> {
862 const fn new(output: &'a mut [u8]) -> Self {
863 Self {
864 output,
865 position: 0,
866 }
867 }
868}
869
870impl Sink for Writer<'_> {
871 fn put(&mut self, bytes: &[u8]) -> Result<(), CodecError> {
872 let end = self
873 .position
874 .checked_add(bytes.len())
875 .ok_or(CodecError::LengthOverflow)?;
876 let available = self.output.len();
877 let Some(destination) = self.output.get_mut(self.position..end) else {
878 return Err(CodecError::OutputTooSmall {
879 required: end,
880 available,
881 });
882 };
883 destination.copy_from_slice(bytes);
884 self.position = end;
885 Ok(())
886 }
887}
888
889struct Reader<'a> {
890 input: &'a [u8],
891 position: usize,
892 invalid_field: bool,
893}
894
895impl<'a> Reader<'a> {
896 const fn new(input: &'a [u8]) -> Self {
897 Self {
898 input,
899 position: 0,
900 invalid_field: false,
901 }
902 }
903
904 const fn remaining(&self) -> usize {
905 self.input.len().saturating_sub(self.position)
906 }
907
908 fn remaining_bytes(&self) -> &'a [u8] {
909 match self.input.get(self.position..) {
910 Some(bytes) => bytes,
911 None => &[],
912 }
913 }
914
915 fn take(&mut self, length: usize) -> Result<&'a [u8], CodecError> {
916 let end = self
917 .position
918 .checked_add(length)
919 .ok_or_else(|| decode_error(DecodeClass::MissingRequiredField))?;
920 let Some(bytes) = self.input.get(self.position..end) else {
921 return Err(decode_error(DecodeClass::MissingRequiredField));
922 };
923 self.position = end;
924 Ok(bytes)
925 }
926
927 fn take_fixed<const N: usize>(&mut self) -> Result<[u8; N], CodecError> {
928 let mut output = [0; N];
929 output.copy_from_slice(self.take(N)?);
930 Ok(output)
931 }
932
933 fn take_u8(&mut self) -> Result<u8, CodecError> {
934 Ok(u8::from_be_bytes(self.take_fixed()?))
935 }
936
937 fn take_u16(&mut self) -> Result<u16, CodecError> {
938 Ok(u16::from_be_bytes(self.take_fixed()?))
939 }
940
941 fn take_u32(&mut self) -> Result<u32, CodecError> {
942 Ok(u32::from_be_bytes(self.take_fixed()?))
943 }
944
945 fn take_u64(&mut self) -> Result<u64, CodecError> {
946 Ok(u64::from_be_bytes(self.take_fixed()?))
947 }
948
949 fn take_generation(&mut self) -> Result<Generation, CodecError> {
950 let raw = self.take_u64()?;
951 if let Some(value) = Generation::new(raw) {
952 return Ok(value);
953 }
954 self.invalid_field = true;
955 Generation::new(1).ok_or(decode_error(DecodeClass::InvalidField))
956 }
957
958 fn take_binding_epoch(&mut self) -> Result<BindingEpoch, CodecError> {
959 Ok(BindingEpoch::new(
960 ConnectionIncarnation::new(self.take_u64()?, self.take_u64()?),
961 self.take_generation()?,
962 ))
963 }
964
965 fn take_option_u64(&mut self) -> Result<Option<u64>, CodecError> {
966 match self.take_u8()? {
967 0 => Ok(None),
968 1 => self.take_u64().map(Some),
969 _ => Err(decode_error(DecodeClass::InvalidField)),
970 }
971 }
972
973 fn take_option_binding_epoch(&mut self) -> Result<Option<BindingEpoch>, CodecError> {
974 match self.take_u8()? {
975 0 => Ok(None),
976 1 => self.take_binding_epoch().map(Some),
977 _ => Err(decode_error(DecodeClass::InvalidField)),
978 }
979 }
980
981 fn take_bytes(&mut self) -> Result<Vec<u8>, CodecError> {
982 let length: usize = self
983 .take_u32()?
984 .try_into()
985 .map_err(|_| decode_error(DecodeClass::MissingRequiredField))?;
986 Ok(self.take(length)?.to_vec())
987 }
988
989 fn require_fixed_list(&self, count: u64, width: usize) -> Result<(), CodecError> {
990 let width =
991 u128::try_from(width).map_err(|_| decode_error(DecodeClass::MissingRequiredField))?;
992 let remaining = u128::try_from(self.remaining())
993 .map_err(|_| decode_error(DecodeClass::MissingRequiredField))?;
994 let required = u128::from(count)
995 .checked_mul(width)
996 .ok_or_else(|| decode_error(DecodeClass::MissingRequiredField))?;
997 if required > remaining {
998 return Err(decode_error(DecodeClass::MissingRequiredField));
999 }
1000 Ok(())
1001 }
1002
1003 const fn finish(self) -> Result<(), CodecError> {
1004 if self.position != self.input.len() {
1005 return Err(decode_error(DecodeClass::CanonicalEncoding));
1006 }
1007 if self.invalid_field {
1008 return Err(decode_error(DecodeClass::InvalidField));
1009 }
1010 Ok(())
1011 }
1012}