1use std::collections::HashSet;
8use std::error::Error;
9use std::fmt;
10
11use super::bridge::WireBridgeMetadata as SemanticWireBridgeMetadata;
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14pub enum CanonicalProtobufErrorCategory {
16 UnknownField,
18 DuplicateSingular,
20 NoncanonicalBytes,
22 InvalidOneof,
24 MissingRequired,
26 InvalidWireEdge,
28 DefaultEmission,
30 Malformed,
32}
33
34impl CanonicalProtobufErrorCategory {
35 #[must_use]
36 pub fn as_str(self) -> &'static str {
38 match self {
39 Self::UnknownField => "unknown_field",
40 Self::DuplicateSingular => "duplicate_singular",
41 Self::NoncanonicalBytes => "noncanonical_bytes",
42 Self::InvalidOneof => "invalid_oneof",
43 Self::MissingRequired => "missing_required",
44 Self::InvalidWireEdge => "invalid_wire_edge",
45 Self::DefaultEmission => "default_emission",
46 Self::Malformed => "malformed",
47 }
48 }
49}
50
51#[derive(Debug, Clone, PartialEq, Eq)]
52pub struct CanonicalProtobufError {
54 pub category: CanonicalProtobufErrorCategory,
56 message: String,
57}
58
59impl CanonicalProtobufError {
60 fn new(category: CanonicalProtobufErrorCategory, message: impl Into<String>) -> Self {
61 Self {
62 category,
63 message: message.into(),
64 }
65 }
66}
67
68impl fmt::Display for CanonicalProtobufError {
69 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
70 write!(f, "{}: {}", self.category.as_str(), self.message)
71 }
72}
73
74impl Error for CanonicalProtobufError {}
75
76#[derive(Debug, Clone, PartialEq, Eq)]
77pub struct CanonicalWireBridgeMetadata {
79 pub seq: u64,
81 pub cursor: u64,
83 pub idempotency_key: String,
85 pub attempt: u32,
87 pub max_attempts: u32,
89 pub timestamp_ms: Option<u64>,
91 pub ack_for_seq: Option<u64>,
93 pub request_id: Option<String>,
95}
96
97#[derive(Debug, Clone, PartialEq, Eq)]
98pub enum CanonicalWireBridgeDataBody {
100 Value(Vec<u8>),
102 WireEdge(CanonicalWireEdgeFrame),
104}
105
106#[derive(Debug, Clone, PartialEq, Eq)]
107pub struct CanonicalWireEdgeFrame {
109 pub kind: CanonicalWireEdgeKind,
111 pub edge_id: String,
113 pub cause_id: String,
115 pub value: Option<Vec<u8>>,
117}
118
119#[derive(Debug, Clone, Copy, PartialEq, Eq)]
120pub enum CanonicalWireEdgeKind {
122 Dirty,
124 Data,
126}
127
128#[derive(Debug, Clone, PartialEq, Eq)]
129pub enum CanonicalWireBridgePayload {
131 Start,
133 Data(CanonicalWireBridgeDataBody),
135 Ack,
137 Nack {
139 error: Option<Vec<u8>>,
141 },
142 Status {
144 status: Vec<u8>,
146 },
147 Error {
149 error: Vec<u8>,
151 },
152 Close {
154 reason: Option<Vec<u8>>,
156 },
157}
158
159#[derive(Debug, Clone, PartialEq, Eq)]
160pub struct CanonicalWireBridgeEnvelope {
162 pub session_id: String,
164 pub metadata: CanonicalWireBridgeMetadata,
166 pub payload: CanonicalWireBridgePayload,
168}
169
170#[derive(Debug, Clone, Copy, PartialEq, Eq)]
171pub struct WireBridgeProtobufHelperShape {
173 pub byte_specific: bool,
175 pub semantic_wire_bridge_dto: bool,
177 pub core_wire_bridge_options: bool,
179 pub protocol_surface: bool,
181 pub value_codec_registry: bool,
183}
184
185pub const WIRE_BRIDGE_PROTOBUF_HELPER_SHAPE: WireBridgeProtobufHelperShape =
187 WireBridgeProtobufHelperShape {
188 byte_specific: true,
189 semantic_wire_bridge_dto: true,
190 core_wire_bridge_options: false,
191 protocol_surface: false,
192 value_codec_registry: false,
193 };
194
195#[derive(Debug, Clone, PartialEq, Eq)]
196pub enum WireBridgeProtobufDataBody {
198 Value(Vec<u8>),
200 WireEdge(CanonicalWireEdgeFrame),
202}
203
204#[derive(Debug, Clone, PartialEq, Eq)]
205pub enum WireBridgeProtobufPayload {
207 Start,
209 Data(WireBridgeProtobufDataBody),
211 Ack,
213 Nack {
215 error: Option<Vec<u8>>,
217 },
218 Status {
220 status: Vec<u8>,
222 },
223 Error {
225 error: Vec<u8>,
227 },
228 Close {
230 reason: Option<Vec<u8>>,
232 },
233}
234
235#[derive(Debug, Clone, PartialEq, Eq)]
236pub struct WireBridgeProtobufEnvelope {
238 pub session_id: String,
240 pub metadata: SemanticWireBridgeMetadata,
242 pub payload: WireBridgeProtobufPayload,
244}
245
246#[derive(Debug, Clone, Copy, PartialEq, Eq)]
247pub enum WireBridgeProtobufStatusKind {
249 Valid,
251 Invalid,
253}
254
255#[derive(Debug, Clone, PartialEq, Eq)]
256pub struct WireBridgeProtobufStatus {
258 pub kind: WireBridgeProtobufStatusKind,
260}
261
262#[derive(Debug, Clone, PartialEq, Eq)]
263pub struct WireBridgeProtobufIssue {
265 pub category: CanonicalProtobufErrorCategory,
267 pub message: String,
269}
270
271impl From<CanonicalProtobufError> for WireBridgeProtobufIssue {
272 fn from(error: CanonicalProtobufError) -> Self {
273 Self {
274 category: error.category,
275 message: error.to_string(),
276 }
277 }
278}
279
280#[derive(Debug, Clone, PartialEq, Eq)]
281pub struct WireBridgeProtobufDecode {
283 pub envelope: Option<WireBridgeProtobufEnvelope>,
285 pub status: WireBridgeProtobufStatus,
287 pub issues: Vec<WireBridgeProtobufIssue>,
289}
290
291#[derive(Debug, Clone, PartialEq, Eq)]
292pub struct WireBridgeProtobufEncode {
294 pub bytes: Option<Vec<u8>>,
296 pub status: WireBridgeProtobufStatus,
298 pub issues: Vec<WireBridgeProtobufIssue>,
300}
301
302pub fn encode_canonical_wire_bridge_envelope(
304 envelope: &CanonicalWireBridgeEnvelope,
305) -> Result<Vec<u8>, CanonicalProtobufError> {
306 validate_wire_bridge_envelope(envelope)?;
307 let mut out = Writer::default();
308 out.string_field(1, &envelope.session_id);
309 out.message_field(2, &encode_metadata(&envelope.metadata));
310 match &envelope.payload {
311 CanonicalWireBridgePayload::Start => out.message_field(3, &[]),
312 CanonicalWireBridgePayload::Data(body) => {
313 out.message_field(4, &encode_data_payload(body)?);
314 }
315 CanonicalWireBridgePayload::Ack => out.message_field(5, &[]),
316 CanonicalWireBridgePayload::Nack { error } => {
317 out.message_field(6, &encode_optional_bytes_message(1, error.as_deref())?);
318 }
319 CanonicalWireBridgePayload::Status { status } => {
320 out.message_field(7, &encode_required_bytes_message(1, status));
321 }
322 CanonicalWireBridgePayload::Error { error } => {
323 out.message_field(8, &encode_required_bytes_message(1, error));
324 }
325 CanonicalWireBridgePayload::Close { reason } => {
326 out.message_field(9, &encode_optional_bytes_message(1, reason.as_deref())?);
327 }
328 }
329 Ok(out.finish())
330}
331
332pub fn decode_canonical_wire_bridge_envelope(
334 bytes: &[u8],
335) -> Result<CanonicalWireBridgeEnvelope, CanonicalProtobufError> {
336 let envelope = parse_wire_bridge_envelope(bytes)?;
337 validate_wire_bridge_envelope(&envelope)?;
338 let canonical = encode_canonical_wire_bridge_envelope(&envelope)?;
339 if canonical != bytes {
340 return Err(CanonicalProtobufError::new(
341 CanonicalProtobufErrorCategory::NoncanonicalBytes,
342 "WireBridgeEnvelope bytes are not canonical deterministic protobuf",
343 ));
344 }
345 Ok(envelope)
346}
347
348pub fn encode_canonical_wire_edge_frame(
350 frame: &CanonicalWireEdgeFrame,
351) -> Result<Vec<u8>, CanonicalProtobufError> {
352 validate_wire_edge_frame(frame)?;
353 Ok(encode_wire_edge_frame(frame))
354}
355
356pub fn decode_canonical_wire_edge_frame(
358 bytes: &[u8],
359) -> Result<CanonicalWireEdgeFrame, CanonicalProtobufError> {
360 let frame = parse_wire_edge_frame(bytes)?;
361 validate_wire_edge_frame(&frame)?;
362 let canonical = encode_wire_edge_frame(&frame);
363 if canonical != bytes {
364 return Err(CanonicalProtobufError::new(
365 CanonicalProtobufErrorCategory::NoncanonicalBytes,
366 "WireEdgeFrame bytes are not canonical deterministic protobuf",
367 ));
368 }
369 Ok(frame)
370}
371
372#[must_use]
373pub fn decode_wire_bridge_protobuf_bytes(bytes: &[u8]) -> WireBridgeProtobufDecode {
375 match decode_canonical_wire_bridge_envelope(bytes) {
376 Ok(envelope) => WireBridgeProtobufDecode {
377 envelope: Some(canonical_to_protobuf_envelope(envelope)),
378 status: WireBridgeProtobufStatus {
379 kind: WireBridgeProtobufStatusKind::Valid,
380 },
381 issues: Vec::new(),
382 },
383 Err(error) => WireBridgeProtobufDecode {
384 envelope: None,
385 status: WireBridgeProtobufStatus {
386 kind: WireBridgeProtobufStatusKind::Invalid,
387 },
388 issues: vec![error.into()],
389 },
390 }
391}
392
393#[must_use]
394pub fn encode_wire_bridge_protobuf_bytes(
396 envelope: &WireBridgeProtobufEnvelope,
397) -> WireBridgeProtobufEncode {
398 match protobuf_to_canonical_envelope(envelope)
399 .and_then(|canonical| encode_canonical_wire_bridge_envelope(&canonical))
400 {
401 Ok(bytes) => WireBridgeProtobufEncode {
402 bytes: Some(bytes),
403 status: WireBridgeProtobufStatus {
404 kind: WireBridgeProtobufStatusKind::Valid,
405 },
406 issues: Vec::new(),
407 },
408 Err(error) => WireBridgeProtobufEncode {
409 bytes: None,
410 status: WireBridgeProtobufStatus {
411 kind: WireBridgeProtobufStatusKind::Invalid,
412 },
413 issues: vec![error.into()],
414 },
415 }
416}
417
418fn canonical_to_protobuf_envelope(
419 envelope: CanonicalWireBridgeEnvelope,
420) -> WireBridgeProtobufEnvelope {
421 WireBridgeProtobufEnvelope {
422 session_id: envelope.session_id,
423 metadata: SemanticWireBridgeMetadata {
424 seq: envelope.metadata.seq,
425 cursor: envelope.metadata.cursor,
426 idempotency_key: envelope.metadata.idempotency_key,
427 attempt: envelope.metadata.attempt,
428 max_attempts: envelope.metadata.max_attempts,
429 timestamp_ms: envelope.metadata.timestamp_ms,
430 ack_for_seq: envelope.metadata.ack_for_seq,
431 request_id: envelope.metadata.request_id,
432 },
433 payload: match envelope.payload {
434 CanonicalWireBridgePayload::Start => WireBridgeProtobufPayload::Start,
435 CanonicalWireBridgePayload::Data(CanonicalWireBridgeDataBody::Value(value)) => {
436 WireBridgeProtobufPayload::Data(WireBridgeProtobufDataBody::Value(value))
437 }
438 CanonicalWireBridgePayload::Data(CanonicalWireBridgeDataBody::WireEdge(frame)) => {
439 WireBridgeProtobufPayload::Data(WireBridgeProtobufDataBody::WireEdge(frame))
440 }
441 CanonicalWireBridgePayload::Ack => WireBridgeProtobufPayload::Ack,
442 CanonicalWireBridgePayload::Nack { error } => WireBridgeProtobufPayload::Nack { error },
443 CanonicalWireBridgePayload::Status { status } => {
444 WireBridgeProtobufPayload::Status { status }
445 }
446 CanonicalWireBridgePayload::Error { error } => {
447 WireBridgeProtobufPayload::Error { error }
448 }
449 CanonicalWireBridgePayload::Close { reason } => {
450 WireBridgeProtobufPayload::Close { reason }
451 }
452 },
453 }
454}
455
456fn protobuf_to_canonical_envelope(
457 envelope: &WireBridgeProtobufEnvelope,
458) -> Result<CanonicalWireBridgeEnvelope, CanonicalProtobufError> {
459 let canonical = CanonicalWireBridgeEnvelope {
460 session_id: envelope.session_id.clone(),
461 metadata: CanonicalWireBridgeMetadata {
462 seq: envelope.metadata.seq,
463 cursor: envelope.metadata.cursor,
464 idempotency_key: envelope.metadata.idempotency_key.clone(),
465 attempt: envelope.metadata.attempt,
466 max_attempts: envelope.metadata.max_attempts,
467 timestamp_ms: envelope.metadata.timestamp_ms,
468 ack_for_seq: envelope.metadata.ack_for_seq,
469 request_id: envelope.metadata.request_id.clone(),
470 },
471 payload: match &envelope.payload {
472 WireBridgeProtobufPayload::Start => CanonicalWireBridgePayload::Start,
473 WireBridgeProtobufPayload::Data(WireBridgeProtobufDataBody::Value(value)) => {
474 CanonicalWireBridgePayload::Data(CanonicalWireBridgeDataBody::Value(value.clone()))
475 }
476 WireBridgeProtobufPayload::Data(WireBridgeProtobufDataBody::WireEdge(frame)) => {
477 CanonicalWireBridgePayload::Data(CanonicalWireBridgeDataBody::WireEdge(
478 frame.clone(),
479 ))
480 }
481 WireBridgeProtobufPayload::Ack => CanonicalWireBridgePayload::Ack,
482 WireBridgeProtobufPayload::Nack { error } => CanonicalWireBridgePayload::Nack {
483 error: error.clone(),
484 },
485 WireBridgeProtobufPayload::Status { status } => CanonicalWireBridgePayload::Status {
486 status: status.clone(),
487 },
488 WireBridgeProtobufPayload::Error { error } => CanonicalWireBridgePayload::Error {
489 error: error.clone(),
490 },
491 WireBridgeProtobufPayload::Close { reason } => CanonicalWireBridgePayload::Close {
492 reason: reason.clone(),
493 },
494 },
495 };
496 validate_wire_bridge_envelope(&canonical)?;
497 Ok(canonical)
498}
499
500fn parse_wire_bridge_envelope(
501 bytes: &[u8],
502) -> Result<CanonicalWireBridgeEnvelope, CanonicalProtobufError> {
503 let fields = read_fields(
504 bytes,
505 &[
506 (1, 2),
507 (2, 2),
508 (3, 2),
509 (4, 2),
510 (5, 2),
511 (6, 2),
512 (7, 2),
513 (8, 2),
514 (9, 2),
515 ],
516 "WireBridgeEnvelope",
517 )?;
518 let session = bytes_field(&fields, 1);
519 let metadata = bytes_field(&fields, 2);
520 let payload_fields: Vec<&Field> = fields
521 .iter()
522 .filter(|field| (3..=9).contains(&field.no))
523 .collect();
524 if session.is_none() || metadata.is_none() || payload_fields.is_empty() {
525 return Err(CanonicalProtobufError::new(
526 CanonicalProtobufErrorCategory::MissingRequired,
527 "WireBridgeEnvelope missing required fields",
528 ));
529 }
530 if payload_fields.len() != 1 {
531 return Err(CanonicalProtobufError::new(
532 CanonicalProtobufErrorCategory::InvalidOneof,
533 "WireBridgeEnvelope payload oneof has multiple cases",
534 ));
535 }
536 let payload_field = payload_fields[0];
537 let payload_bytes = payload_field.as_bytes()?;
538 Ok(CanonicalWireBridgeEnvelope {
539 session_id: utf8_string(session.unwrap(), "session_id")?,
540 metadata: parse_metadata(metadata.unwrap())?,
541 payload: parse_envelope_payload(payload_field.no, payload_bytes)?,
542 })
543}
544
545fn parse_envelope_payload(
546 field_no: u32,
547 bytes: &[u8],
548) -> Result<CanonicalWireBridgePayload, CanonicalProtobufError> {
549 match field_no {
550 3 => {
551 require_empty_message(bytes, "start")?;
552 Ok(CanonicalWireBridgePayload::Start)
553 }
554 4 => Ok(CanonicalWireBridgePayload::Data(parse_data_payload(bytes)?)),
555 5 => {
556 require_empty_message(bytes, "ack")?;
557 Ok(CanonicalWireBridgePayload::Ack)
558 }
559 6 => Ok(CanonicalWireBridgePayload::Nack {
560 error: parse_optional_bytes_payload(bytes, "nack")?,
561 }),
562 7 => Ok(CanonicalWireBridgePayload::Status {
563 status: parse_required_bytes_payload(bytes, "status")?,
564 }),
565 8 => Ok(CanonicalWireBridgePayload::Error {
566 error: parse_required_bytes_payload(bytes, "error")?,
567 }),
568 9 => Ok(CanonicalWireBridgePayload::Close {
569 reason: parse_optional_bytes_payload(bytes, "close")?,
570 }),
571 _ => Err(CanonicalProtobufError::new(
572 CanonicalProtobufErrorCategory::UnknownField,
573 "unknown envelope payload field",
574 )),
575 }
576}
577
578fn parse_metadata(bytes: &[u8]) -> Result<CanonicalWireBridgeMetadata, CanonicalProtobufError> {
579 let fields = read_fields(
580 bytes,
581 &[
582 (1, 0),
583 (2, 0),
584 (3, 2),
585 (4, 0),
586 (5, 0),
587 (6, 0),
588 (7, 0),
589 (8, 2),
590 ],
591 "WireBridgeMetadata",
592 )?;
593 let seq = uint_field(&fields, 1);
594 let cursor = uint_field(&fields, 2);
595 let key = bytes_field(&fields, 3);
596 let attempt = uint_field(&fields, 4);
597 let max_attempts = uint_field(&fields, 5);
598 if seq.is_none()
599 || cursor.is_none()
600 || key.is_none()
601 || attempt.is_none()
602 || max_attempts.is_none()
603 {
604 return Err(CanonicalProtobufError::new(
605 CanonicalProtobufErrorCategory::MissingRequired,
606 "WireBridgeMetadata missing required fields",
607 ));
608 }
609 let timestamp_ms = uint_field(&fields, 6);
610 let ack_for_seq = uint_field(&fields, 7);
611 let request_id = bytes_field(&fields, 8);
612 if timestamp_ms == Some(0) || ack_for_seq == Some(0) || request_id == Some(&[][..]) {
613 return Err(CanonicalProtobufError::new(
614 CanonicalProtobufErrorCategory::DefaultEmission,
615 "optional metadata default value was emitted",
616 ));
617 }
618 Ok(CanonicalWireBridgeMetadata {
619 seq: seq.unwrap(),
620 cursor: cursor.unwrap(),
621 idempotency_key: utf8_string(key.unwrap(), "idempotency_key")?,
622 attempt: uint32(attempt.unwrap(), "attempt")?,
623 max_attempts: uint32(max_attempts.unwrap(), "max_attempts")?,
624 timestamp_ms,
625 ack_for_seq,
626 request_id: request_id
627 .map(|value| utf8_string(value, "request_id"))
628 .transpose()?,
629 })
630}
631
632fn parse_data_payload(bytes: &[u8]) -> Result<CanonicalWireBridgeDataBody, CanonicalProtobufError> {
633 let fields = read_fields(bytes, &[(1, 2), (2, 2)], "WireBridgeDataPayload")?;
634 let value = bytes_field(&fields, 1);
635 let wire_edge = bytes_field(&fields, 2);
636 match (value, wire_edge) {
637 (Some(_), Some(_)) => Err(CanonicalProtobufError::new(
638 CanonicalProtobufErrorCategory::InvalidOneof,
639 "WireBridgeDataPayload body has multiple cases",
640 )),
641 (Some(value), None) => Ok(CanonicalWireBridgeDataBody::Value(value.to_vec())),
642 (None, Some(wire_edge)) => Ok(CanonicalWireBridgeDataBody::WireEdge(
643 parse_wire_edge_frame(wire_edge)?,
644 )),
645 (None, None) => Err(CanonicalProtobufError::new(
646 CanonicalProtobufErrorCategory::MissingRequired,
647 "WireBridgeDataPayload missing body",
648 )),
649 }
650}
651
652fn parse_wire_edge_frame(bytes: &[u8]) -> Result<CanonicalWireEdgeFrame, CanonicalProtobufError> {
653 let fields = read_fields(bytes, &[(1, 0), (2, 2), (3, 2), (4, 2)], "WireEdgeFrame")?;
654 let kind = uint_field(&fields, 1);
655 let edge = bytes_field(&fields, 2);
656 let cause = bytes_field(&fields, 3);
657 let value = bytes_field(&fields, 4);
658 if kind.is_none() || edge.is_none() || cause.is_none() {
659 return Err(CanonicalProtobufError::new(
660 CanonicalProtobufErrorCategory::MissingRequired,
661 "WireEdgeFrame missing required fields",
662 ));
663 }
664 let edge_id = utf8_string(edge.unwrap(), "edge_id")?;
665 let cause_id = utf8_string(cause.unwrap(), "cause_id")?;
666 match kind.unwrap() {
667 1 => {
668 if value.is_some() {
669 return Err(CanonicalProtobufError::new(
670 CanonicalProtobufErrorCategory::InvalidWireEdge,
671 "DIRTY WireEdgeFrame must not carry value",
672 ));
673 }
674 Ok(CanonicalWireEdgeFrame {
675 kind: CanonicalWireEdgeKind::Dirty,
676 edge_id,
677 cause_id,
678 value: None,
679 })
680 }
681 2 => {
682 let value = value.ok_or_else(|| {
683 CanonicalProtobufError::new(
684 CanonicalProtobufErrorCategory::InvalidWireEdge,
685 "DATA WireEdgeFrame requires value",
686 )
687 })?;
688 Ok(CanonicalWireEdgeFrame {
689 kind: CanonicalWireEdgeKind::Data,
690 edge_id,
691 cause_id,
692 value: Some(value.to_vec()),
693 })
694 }
695 _ => Err(CanonicalProtobufError::new(
696 CanonicalProtobufErrorCategory::InvalidWireEdge,
697 "WireEdgeFrame kind is invalid",
698 )),
699 }
700}
701
702fn validate_wire_bridge_envelope(
703 envelope: &CanonicalWireBridgeEnvelope,
704) -> Result<(), CanonicalProtobufError> {
705 if envelope.session_id.is_empty()
706 || envelope.metadata.seq == 0
707 || envelope.metadata.attempt == 0
708 || envelope.metadata.max_attempts < envelope.metadata.attempt
709 || envelope.metadata.idempotency_key.is_empty()
710 {
711 return Err(CanonicalProtobufError::new(
712 CanonicalProtobufErrorCategory::MissingRequired,
713 "WireBridgeEnvelope required semantics are invalid",
714 ));
715 }
716 if matches!(
717 envelope.payload,
718 CanonicalWireBridgePayload::Ack | CanonicalWireBridgePayload::Nack { .. }
719 ) && envelope.metadata.ack_for_seq.is_none()
720 {
721 return Err(CanonicalProtobufError::new(
722 CanonicalProtobufErrorCategory::MissingRequired,
723 "ACK/NACK requires metadata.ack_for_seq",
724 ));
725 }
726 if envelope.metadata.timestamp_ms == Some(0)
727 || envelope.metadata.ack_for_seq == Some(0)
728 || envelope.metadata.request_id.as_deref() == Some("")
729 {
730 return Err(CanonicalProtobufError::new(
731 CanonicalProtobufErrorCategory::DefaultEmission,
732 "optional metadata default value was emitted",
733 ));
734 }
735 if let CanonicalWireBridgePayload::Data(CanonicalWireBridgeDataBody::WireEdge(frame)) =
736 &envelope.payload
737 {
738 validate_wire_edge_frame(frame)?;
739 }
740 match &envelope.payload {
741 CanonicalWireBridgePayload::Nack { error } if error.as_deref() == Some(&[]) => {
742 return Err(CanonicalProtobufError::new(
743 CanonicalProtobufErrorCategory::DefaultEmission,
744 "nack optional bytes default value was emitted",
745 ));
746 }
747 CanonicalWireBridgePayload::Status { status } if status.is_empty() => {
748 return Err(CanonicalProtobufError::new(
749 CanonicalProtobufErrorCategory::MissingRequired,
750 "status payload bytes must be non-empty",
751 ));
752 }
753 CanonicalWireBridgePayload::Error { error } if error.is_empty() => {
754 return Err(CanonicalProtobufError::new(
755 CanonicalProtobufErrorCategory::MissingRequired,
756 "error payload bytes must be non-empty",
757 ));
758 }
759 CanonicalWireBridgePayload::Close { reason } if reason.as_deref() == Some(&[]) => {
760 return Err(CanonicalProtobufError::new(
761 CanonicalProtobufErrorCategory::DefaultEmission,
762 "close optional bytes default value was emitted",
763 ));
764 }
765 _ => {}
766 }
767 Ok(())
768}
769
770fn validate_wire_edge_frame(frame: &CanonicalWireEdgeFrame) -> Result<(), CanonicalProtobufError> {
771 if frame.edge_id.is_empty() || frame.cause_id.is_empty() {
772 return Err(CanonicalProtobufError::new(
773 CanonicalProtobufErrorCategory::MissingRequired,
774 "WireEdgeFrame edge_id/cause_id must be non-empty",
775 ));
776 }
777 match frame.kind {
778 CanonicalWireEdgeKind::Dirty if frame.value.is_some() => Err(CanonicalProtobufError::new(
779 CanonicalProtobufErrorCategory::InvalidWireEdge,
780 "DIRTY WireEdgeFrame must not carry value",
781 )),
782 CanonicalWireEdgeKind::Data if frame.value.is_none() => Err(CanonicalProtobufError::new(
783 CanonicalProtobufErrorCategory::InvalidWireEdge,
784 "DATA WireEdgeFrame requires value",
785 )),
786 _ => Ok(()),
787 }
788}
789
790fn encode_metadata(metadata: &CanonicalWireBridgeMetadata) -> Vec<u8> {
791 let mut out = Writer::default();
792 out.varint_field(1, metadata.seq);
793 out.varint_field(2, metadata.cursor);
794 out.string_field(3, &metadata.idempotency_key);
795 out.varint_field(4, u64::from(metadata.attempt));
796 out.varint_field(5, u64::from(metadata.max_attempts));
797 if let Some(timestamp_ms) = metadata.timestamp_ms {
798 out.varint_field(6, timestamp_ms);
799 }
800 if let Some(ack_for_seq) = metadata.ack_for_seq {
801 out.varint_field(7, ack_for_seq);
802 }
803 if let Some(request_id) = &metadata.request_id {
804 out.string_field(8, request_id);
805 }
806 out.finish()
807}
808
809fn encode_data_payload(
810 body: &CanonicalWireBridgeDataBody,
811) -> Result<Vec<u8>, CanonicalProtobufError> {
812 let mut out = Writer::default();
813 match body {
814 CanonicalWireBridgeDataBody::Value(value) => out.bytes_field(1, value),
815 CanonicalWireBridgeDataBody::WireEdge(frame) => {
816 out.message_field(2, &encode_canonical_wire_edge_frame(frame)?);
817 }
818 }
819 Ok(out.finish())
820}
821
822fn encode_wire_edge_frame(frame: &CanonicalWireEdgeFrame) -> Vec<u8> {
823 let mut out = Writer::default();
824 out.varint_field(
825 1,
826 match frame.kind {
827 CanonicalWireEdgeKind::Dirty => 1,
828 CanonicalWireEdgeKind::Data => 2,
829 },
830 );
831 out.string_field(2, &frame.edge_id);
832 out.string_field(3, &frame.cause_id);
833 if let Some(value) = &frame.value {
834 out.bytes_field(4, value);
835 }
836 out.finish()
837}
838
839fn encode_required_bytes_message(field_no: u32, value: &[u8]) -> Vec<u8> {
840 let mut out = Writer::default();
841 out.bytes_field(field_no, value);
842 out.finish()
843}
844
845fn encode_optional_bytes_message(
846 field_no: u32,
847 value: Option<&[u8]>,
848) -> Result<Vec<u8>, CanonicalProtobufError> {
849 let mut out = Writer::default();
850 if let Some(value) = value {
851 if value.is_empty() {
852 return Err(CanonicalProtobufError::new(
853 CanonicalProtobufErrorCategory::DefaultEmission,
854 "optional bytes default value must be omitted",
855 ));
856 }
857 out.bytes_field(field_no, value);
858 }
859 Ok(out.finish())
860}
861
862fn parse_required_bytes_payload(
863 bytes: &[u8],
864 name: &str,
865) -> Result<Vec<u8>, CanonicalProtobufError> {
866 let fields = read_fields(bytes, &[(1, 2)], &format!("WireBridge{name}Payload"))?;
867 let value = bytes_field(&fields, 1).ok_or_else(|| {
868 CanonicalProtobufError::new(
869 CanonicalProtobufErrorCategory::MissingRequired,
870 format!("{name} payload missing required bytes"),
871 )
872 })?;
873 if value.is_empty() {
874 return Err(CanonicalProtobufError::new(
875 CanonicalProtobufErrorCategory::MissingRequired,
876 format!("{name} payload bytes must be non-empty"),
877 ));
878 }
879 Ok(value.to_vec())
880}
881
882fn parse_optional_bytes_payload(
883 bytes: &[u8],
884 name: &str,
885) -> Result<Option<Vec<u8>>, CanonicalProtobufError> {
886 let fields = read_fields(bytes, &[(1, 2)], &format!("WireBridge{name}Payload"))?;
887 let value = bytes_field(&fields, 1);
888 if value == Some(&[]) {
889 return Err(CanonicalProtobufError::new(
890 CanonicalProtobufErrorCategory::DefaultEmission,
891 format!("{name} optional bytes default value was emitted"),
892 ));
893 }
894 Ok(value.map(<[u8]>::to_vec))
895}
896
897fn require_empty_message(bytes: &[u8], name: &str) -> Result<(), CanonicalProtobufError> {
898 if bytes.is_empty() {
899 Ok(())
900 } else {
901 Err(CanonicalProtobufError::new(
902 CanonicalProtobufErrorCategory::UnknownField,
903 format!("{name} payload must be empty"),
904 ))
905 }
906}
907
908#[derive(Debug, Clone, PartialEq, Eq)]
909struct Field {
910 no: u32,
911 wire_type: u8,
912 value: FieldValue,
913}
914
915impl Field {
916 fn as_bytes(&self) -> Result<&[u8], CanonicalProtobufError> {
917 match &self.value {
918 FieldValue::Bytes(value) => Ok(value),
919 FieldValue::Varint(_) => Err(CanonicalProtobufError::new(
920 CanonicalProtobufErrorCategory::Malformed,
921 "expected length-delimited field",
922 )),
923 }
924 }
925}
926
927#[derive(Debug, Clone, PartialEq, Eq)]
928enum FieldValue {
929 Varint(u64),
930 Bytes(Vec<u8>),
931}
932
933fn read_fields(
934 bytes: &[u8],
935 allowed: &[(u32, u8)],
936 message_name: &str,
937) -> Result<Vec<Field>, CanonicalProtobufError> {
938 let mut reader = Reader::new(bytes);
939 let mut fields = Vec::new();
940 let mut seen = HashSet::new();
941 while !reader.done() {
942 let key = reader.varint()?;
943 let field_no = u32::try_from(key >> 3).map_err(|_| {
944 CanonicalProtobufError::new(
945 CanonicalProtobufErrorCategory::Malformed,
946 "field number is too large",
947 )
948 })?;
949 let wire_type = u8::try_from(key & 7).expect("wire type fits in u8");
950 let expected = allowed
951 .iter()
952 .find_map(|(no, wt)| (*no == field_no).then_some(*wt));
953 let Some(expected_wire_type) = expected else {
954 return Err(CanonicalProtobufError::new(
955 CanonicalProtobufErrorCategory::UnknownField,
956 format!("{message_name} contains unknown field {field_no}"),
957 ));
958 };
959 if field_no == 0 || wire_type != expected_wire_type {
960 return Err(CanonicalProtobufError::new(
961 CanonicalProtobufErrorCategory::Malformed,
962 format!("{message_name} field {field_no} has wrong wire type"),
963 ));
964 }
965 if !seen.insert(field_no) {
966 return Err(CanonicalProtobufError::new(
967 CanonicalProtobufErrorCategory::DuplicateSingular,
968 format!("{message_name} field {field_no} is duplicated"),
969 ));
970 }
971 let value = match wire_type {
972 0 => FieldValue::Varint(reader.varint()?),
973 2 => FieldValue::Bytes(reader.read_bytes()?),
974 _ => {
975 return Err(CanonicalProtobufError::new(
976 CanonicalProtobufErrorCategory::Malformed,
977 "unsupported wire type",
978 ));
979 }
980 };
981 fields.push(Field {
982 no: field_no,
983 wire_type,
984 value,
985 });
986 }
987 Ok(fields)
988}
989
990fn uint_field(fields: &[Field], no: u32) -> Option<u64> {
991 fields.iter().find_map(|field| match field {
992 Field {
993 no: field_no,
994 value: FieldValue::Varint(value),
995 ..
996 } if *field_no == no => Some(*value),
997 _ => None,
998 })
999}
1000
1001fn bytes_field(fields: &[Field], no: u32) -> Option<&[u8]> {
1002 fields.iter().find_map(|field| match field {
1003 Field {
1004 no: field_no,
1005 value: FieldValue::Bytes(value),
1006 ..
1007 } if *field_no == no => Some(value.as_slice()),
1008 _ => None,
1009 })
1010}
1011
1012fn utf8_string(bytes: &[u8], field: &str) -> Result<String, CanonicalProtobufError> {
1013 let value = std::str::from_utf8(bytes).map_err(|_| {
1014 CanonicalProtobufError::new(
1015 CanonicalProtobufErrorCategory::Malformed,
1016 format!("{field} is not valid utf-8"),
1017 )
1018 })?;
1019 if value.is_empty() {
1020 return Err(CanonicalProtobufError::new(
1021 CanonicalProtobufErrorCategory::MissingRequired,
1022 format!("{field} must be non-empty"),
1023 ));
1024 }
1025 Ok(value.to_owned())
1026}
1027
1028fn uint32(value: u64, field: &str) -> Result<u32, CanonicalProtobufError> {
1029 u32::try_from(value).map_err(|_| {
1030 CanonicalProtobufError::new(
1031 CanonicalProtobufErrorCategory::Malformed,
1032 format!("{field} exceeds uint32"),
1033 )
1034 })
1035}
1036
1037struct Reader<'a> {
1038 bytes: &'a [u8],
1039 offset: usize,
1040}
1041
1042impl<'a> Reader<'a> {
1043 fn new(bytes: &'a [u8]) -> Self {
1044 Self { bytes, offset: 0 }
1045 }
1046
1047 fn done(&self) -> bool {
1048 self.offset == self.bytes.len()
1049 }
1050
1051 fn varint(&mut self) -> Result<u64, CanonicalProtobufError> {
1052 let mut shift = 0u32;
1053 let mut result = 0u64;
1054 for idx in 0..10 {
1055 let byte = *self.bytes.get(self.offset).ok_or_else(|| {
1056 CanonicalProtobufError::new(
1057 CanonicalProtobufErrorCategory::Malformed,
1058 "truncated varint",
1059 )
1060 })?;
1061 self.offset += 1;
1062 if idx == 9 && byte & 0xfe != 0 {
1063 return Err(CanonicalProtobufError::new(
1064 CanonicalProtobufErrorCategory::Malformed,
1065 "varint exceeds 64 bits",
1066 ));
1067 }
1068 result |= u64::from(byte & 0x7f) << shift;
1069 if byte & 0x80 == 0 {
1070 return Ok(result);
1071 }
1072 shift += 7;
1073 }
1074 Err(CanonicalProtobufError::new(
1075 CanonicalProtobufErrorCategory::Malformed,
1076 "varint exceeds 64 bits",
1077 ))
1078 }
1079
1080 fn read_bytes(&mut self) -> Result<Vec<u8>, CanonicalProtobufError> {
1081 let len = usize::try_from(self.varint()?).map_err(|_| {
1082 CanonicalProtobufError::new(
1083 CanonicalProtobufErrorCategory::Malformed,
1084 "length-delimited field is too large",
1085 )
1086 })?;
1087 let end = self.offset.checked_add(len).ok_or_else(|| {
1088 CanonicalProtobufError::new(
1089 CanonicalProtobufErrorCategory::Malformed,
1090 "length-delimited field length overflows",
1091 )
1092 })?;
1093 if end > self.bytes.len() {
1094 return Err(CanonicalProtobufError::new(
1095 CanonicalProtobufErrorCategory::Malformed,
1096 "length-delimited field is truncated",
1097 ));
1098 }
1099 let out = self.bytes[self.offset..end].to_vec();
1100 self.offset = end;
1101 Ok(out)
1102 }
1103}
1104
1105#[derive(Default)]
1106struct Writer {
1107 bytes: Vec<u8>,
1108}
1109
1110impl Writer {
1111 fn varint_field(&mut self, field_no: u32, value: u64) {
1112 self.tag(field_no, 0);
1113 self.varint(value);
1114 }
1115
1116 fn bytes_field(&mut self, field_no: u32, value: &[u8]) {
1117 self.tag(field_no, 2);
1118 self.varint(value.len() as u64);
1119 self.bytes.extend_from_slice(value);
1120 }
1121
1122 fn string_field(&mut self, field_no: u32, value: &str) {
1123 self.bytes_field(field_no, value.as_bytes());
1124 }
1125
1126 fn message_field(&mut self, field_no: u32, value: &[u8]) {
1127 self.bytes_field(field_no, value);
1128 }
1129
1130 fn finish(self) -> Vec<u8> {
1131 self.bytes
1132 }
1133
1134 fn tag(&mut self, field_no: u32, wire_type: u8) {
1135 self.varint(u64::from((field_no << 3) | u32::from(wire_type)));
1136 }
1137
1138 fn varint(&mut self, mut value: u64) {
1139 loop {
1140 let mut byte = (value & 0x7f) as u8;
1141 value >>= 7;
1142 if value != 0 {
1143 byte |= 0x80;
1144 }
1145 self.bytes.push(byte);
1146 if value == 0 {
1147 break;
1148 }
1149 }
1150 }
1151}