1use std::convert::Infallible;
22
23use minicbor::data::Type;
24use minicbor::{Decoder, Encoder};
25use weida_core::Error;
26
27use crate::varint::{VarintError, decode_varint, encode_varint};
28
29pub mod limits {
33 pub const MAX_ENDPOINT_BYTES: usize = 512;
35 pub const MAX_CONTENT_TYPE_BYTES: usize = 256;
37 pub const MAX_TRACEPARENT_BYTES: usize = 128;
39 pub const MAX_TRACESTATE_BYTES: usize = 512;
41 pub const MAX_TOPIC_BYTES: usize = 256;
43 pub const PRODUCER_BYTES: usize = 32;
49 pub const MAX_FILTER_BYTES: usize = 256;
51 pub const MAX_MESSAGE_BYTES: usize = 1024;
53 pub const MAX_LIST_ITEMS: usize = 64;
58 pub const MAX_REPORT_LEVELS: usize = 16;
66 pub const MAX_SKIP_DEPTH: usize = 8;
68}
69
70mod hello_key {
72 pub const VERSIONS: u64 = 0;
73 pub const MAX_HEADER_BYTES: u64 = 1;
74 pub const MAX_TRANSFERS: u64 = 2;
75 pub const CAPABILITIES: u64 = 3;
76 pub const REQUIRED_CAPABILITIES: u64 = 4;
77 pub const GUARANTEES_OFFERED: u64 = 5;
78 pub const GUARANTEES_REQUIRED: u64 = 6;
79}
80
81mod data_key {
83 pub const ENDPOINT: u64 = 0;
84 pub const CONTENT_LEN: u64 = 1;
85 pub const CONTENT_TYPE: u64 = 2;
86 pub const TRACEPARENT: u64 = 3;
87 pub const TRACESTATE: u64 = 4;
88 pub const TOPIC: u64 = 5;
89 pub const SEQUENCE: u64 = 6;
90 pub const PRODUCER: u64 = 7;
91 pub const ACHIEVED: u64 = 8;
92 pub const REPORT_ID: u64 = 9;
93 pub const REPORT: u64 = 10;
94 pub const REPORT_MODE: u64 = 11;
95}
96
97mod error_key {
99 pub const CODE: u64 = 0;
100 pub const MESSAGE: u64 = 1;
101}
102
103mod subscription_key {
105 pub const ENDPOINT: u64 = 0;
106 pub const FILTER: u64 = 1;
107}
108
109mod credit_key {
111 pub const ENDPOINT: u64 = 0;
112 pub const FILTER: u64 = 1;
113 pub const LIMIT: u64 = 2;
114}
115
116mod cursor_key {
118 pub const REPORT_ID: u64 = 0;
119}
120
121pub mod filter {
136 use super::HeaderError;
137
138 pub const SEPARATOR: char = '.';
140 pub const ONE_SEGMENT: &str = "*";
142 pub const REST: &str = "#";
144
145 pub fn matches(topic: &str, filter: &str) -> bool {
167 if filter.is_empty() {
168 return true;
169 }
170 let mut topic_segments = topic.split(SEPARATOR);
171 let mut filter_segments = filter.split(SEPARATOR);
172 loop {
173 let Some(pattern) = filter_segments.next() else {
174 return topic_segments.next().is_none();
176 };
177 if pattern == REST {
180 return true;
181 }
182 let Some(segment) = topic_segments.next() else {
183 return false;
184 };
185 if pattern != ONE_SEGMENT && pattern != segment {
186 return false;
187 }
188 }
189 }
190
191 pub fn validate(filter: &str) -> Result<(), HeaderError> {
196 let mut segments = filter.split(SEPARATOR).peekable();
197 while let Some(segment) = segments.next() {
198 let is_last = segments.peek().is_none();
199 if segment.contains(ONE_SEGMENT) && segment != ONE_SEGMENT {
200 return Err(HeaderError::InvalidFilter(
201 "`*` must occupy a whole segment",
202 ));
203 }
204 if segment.contains(REST) {
205 if segment != REST {
206 return Err(HeaderError::InvalidFilter(
207 "`#` must occupy a whole segment",
208 ));
209 }
210 if !is_last {
211 return Err(HeaderError::InvalidFilter("`#` must be the final segment"));
212 }
213 }
214 }
215 Ok(())
216 }
217}
218
219mod guarantee_key {
221 pub const DELIVERY: u64 = 0;
222 pub const ACKNOWLEDGEMENT: u64 = 1;
223 pub const DURABILITY: u64 = 2;
224 pub const REPLICAS: u64 = 3;
225 pub const ORDERING: u64 = 4;
226 pub const DEDUPLICATION: u64 = 5;
227 pub const DEDUP_WINDOW_MS: u64 = 6;
228 pub const BACKPRESSURE: u64 = 7;
229 pub const PRODUCER_NAMING: u64 = 8;
230 pub const CONTROL_ISOLATED: u64 = 9;
231}
232
233macro_rules! wire_enum {
244 ($(#[$meta:meta])* $name:ident { $($(#[$vmeta:meta])* $variant:ident = $value:literal),+ $(,)? }) => {
245 $(#[$meta])*
246 #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
247 pub enum $name {
248 $($(#[$vmeta])* $variant,)+
249 }
250
251 impl $name {
252 pub fn to_wire(self) -> u64 {
254 match self {
255 $($name::$variant => $value,)+
256 }
257 }
258
259 pub fn from_wire(value: u64) -> Option<$name> {
262 match value {
263 $($value => Some($name::$variant),)+
264 _ => None,
265 }
266 }
267 }
268
269 const _: () = {
274 let values = [$($value as u64),+];
275 let mut i = 1;
276 while i < values.len() {
277 assert!(
278 values[i - 1] < values[i],
279 concat!(
280 stringify!($name),
281 ": wire values must ascend with declaration order, ",
282 "because the derived Ord is the ladder"
283 )
284 );
285 i += 1;
286 }
287 };
288 };
289}
290
291wire_enum! {
292 Delivery {
296 #[default]
298 BestEffort = 0,
299 AtMostOnce = 1,
301 AtLeastOnce = 2,
303 }
304}
305
306wire_enum! {
307 Acknowledgement {
310 None = 0,
312 #[default]
314 TransportReceipt = 1,
315 Accepted = 2,
317 Stored = 3,
319 Replicated = 4,
321 Processed = 5,
323 }
324}
325
326wire_enum! {
327 Durability {
330 #[default]
332 Written = 0,
333 Flushed = 1,
335 }
336}
337
338wire_enum! {
339 OrderingMode {
341 #[default]
343 None = 0,
344 PerProducerDetect = 1,
346 PerProducerReassemble = 2,
348 PerKey = 3,
350 Total = 4,
352 }
353}
354
355wire_enum! {
356 Deduplication {
358 #[default]
360 None = 0,
361 Bounded = 1,
363 Durable = 2,
365 }
366}
367
368wire_enum! {
369 Backpressure {
372 #[default]
374 Block = 0,
375 Reject = 1,
377 Drop = 2,
379 Spill = 3,
381 Coalesce = 4,
383 }
384}
385
386wire_enum! {
387 ProducerNaming {
391 #[default]
395 Fingerprint = 0,
396 Stable = 1,
398 }
399}
400
401wire_enum! {
402 ReportMode {
411 #[default]
414 Progress = 0,
415 FinalOnly = 1,
417 }
418}
419
420#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
431pub enum CursorLevel {
432 Known(Acknowledgement),
434 Application(u64),
436}
437
438impl CursorLevel {
439 pub const APPLICATION_FLOOR: u64 = 16;
441
442 pub fn to_wire(self) -> u64 {
444 match self {
445 CursorLevel::Known(level) => level.to_wire(),
446 CursorLevel::Application(value) => value,
447 }
448 }
449
450 pub fn from_wire(value: u64) -> Option<CursorLevel> {
453 if value >= CursorLevel::APPLICATION_FLOOR {
454 Some(CursorLevel::Application(value))
455 } else {
456 Acknowledgement::from_wire(value).map(CursorLevel::Known)
457 }
458 }
459
460 pub fn application(value: u64) -> Option<CursorLevel> {
463 (value >= CursorLevel::APPLICATION_FLOOR).then_some(CursorLevel::Application(value))
464 }
465}
466
467#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
476pub struct GuaranteeSet {
477 pub delivery: Delivery,
479 pub acknowledgement: Acknowledgement,
481 pub durability: Option<Durability>,
483 pub replicas: Option<u64>,
485 pub ordering: OrderingMode,
487 pub deduplication: Deduplication,
489 pub dedup_window_ms: Option<u64>,
491 pub backpressure: Backpressure,
493 pub producer_naming: ProducerNaming,
495 pub control_isolated: bool,
499}
500
501impl GuaranteeSet {
502 pub const CORE: GuaranteeSet = GuaranteeSet {
504 delivery: Delivery::BestEffort,
505 acknowledgement: Acknowledgement::TransportReceipt,
506 durability: None,
507 replicas: None,
508 ordering: OrderingMode::None,
509 deduplication: Deduplication::None,
510 dedup_window_ms: None,
511 backpressure: Backpressure::Block,
512 producer_naming: ProducerNaming::Fingerprint,
513 control_isolated: false,
514 };
515
516 pub fn is_core(&self) -> bool {
519 *self == GuaranteeSet::CORE
520 }
521
522 fn validate(&self) -> Result<(), HeaderError> {
524 let stored_or_replicated = matches!(
525 self.acknowledgement,
526 Acknowledgement::Stored | Acknowledgement::Replicated
527 );
528 if self.durability.is_some() && !stored_or_replicated {
529 return Err(HeaderError::InvalidGuarantees(
530 "durability without Stored or Replicated",
531 ));
532 }
533 match self.replicas {
534 Some(_) if self.acknowledgement != Acknowledgement::Replicated => {
535 return Err(HeaderError::InvalidGuarantees(
536 "replicas without Replicated",
537 ));
538 }
539 Some(n) if n < 2 => {
540 return Err(HeaderError::InvalidGuarantees(
541 "a replica count below 2 is not a replication",
542 ));
543 }
544 _ => {}
545 }
546 match (self.deduplication, self.dedup_window_ms) {
547 (Deduplication::Bounded, None) => {
548 return Err(HeaderError::InvalidGuarantees(
549 "Bounded deduplication without a window",
550 ));
551 }
552 (level, Some(_)) if level != Deduplication::Bounded => {
553 return Err(HeaderError::InvalidGuarantees(
554 "a dedup window without Bounded deduplication",
555 ));
556 }
557 _ => {}
558 }
559 Ok(())
560 }
561
562 fn encode_into(
564 &self,
565 e: &mut Encoder<Vec<u8>>,
566 ) -> Result<(), minicbor::encode::Error<Infallible>> {
567 let core = GuaranteeSet::CORE;
568 let count = u64::from(self.delivery != core.delivery)
569 + u64::from(self.acknowledgement != core.acknowledgement)
570 + u64::from(self.durability.is_some())
571 + u64::from(self.replicas.is_some())
572 + u64::from(self.ordering != core.ordering)
573 + u64::from(self.deduplication != core.deduplication)
574 + u64::from(self.dedup_window_ms.is_some())
575 + u64::from(self.backpressure != core.backpressure)
576 + u64::from(self.producer_naming != core.producer_naming)
577 + u64::from(self.control_isolated != core.control_isolated);
578 e.map(count)?;
579 if self.delivery != core.delivery {
580 e.u64(guarantee_key::DELIVERY)?
581 .u64(self.delivery.to_wire())?;
582 }
583 if self.acknowledgement != core.acknowledgement {
584 e.u64(guarantee_key::ACKNOWLEDGEMENT)?
585 .u64(self.acknowledgement.to_wire())?;
586 }
587 if let Some(durability) = self.durability {
588 e.u64(guarantee_key::DURABILITY)?
589 .u64(durability.to_wire())?;
590 }
591 if let Some(replicas) = self.replicas {
592 e.u64(guarantee_key::REPLICAS)?.u64(replicas)?;
593 }
594 if self.ordering != core.ordering {
595 e.u64(guarantee_key::ORDERING)?
596 .u64(self.ordering.to_wire())?;
597 }
598 if self.deduplication != core.deduplication {
599 e.u64(guarantee_key::DEDUPLICATION)?
600 .u64(self.deduplication.to_wire())?;
601 }
602 if let Some(window) = self.dedup_window_ms {
603 e.u64(guarantee_key::DEDUP_WINDOW_MS)?.u64(window)?;
604 }
605 if self.backpressure != core.backpressure {
606 e.u64(guarantee_key::BACKPRESSURE)?
607 .u64(self.backpressure.to_wire())?;
608 }
609 if self.producer_naming != core.producer_naming {
610 e.u64(guarantee_key::PRODUCER_NAMING)?
611 .u64(self.producer_naming.to_wire())?;
612 }
613 if self.control_isolated != core.control_isolated {
614 e.u64(guarantee_key::CONTROL_ISOLATED)?
615 .u64(u64::from(self.control_isolated))?;
616 }
617 Ok(())
618 }
619
620 fn decode_from(m: &mut MapReader<'_, '_>) -> Result<GuaranteeSet, HeaderError> {
625 let mut set = GuaranteeSet::CORE;
626 let mut inner = MapReader::new(m.d)?;
627 while let Some(key) = inner.next_key()? {
628 match key {
629 guarantee_key::DELIVERY => set.delivery = level(inner.u64()?, "delivery")?,
630 guarantee_key::ACKNOWLEDGEMENT => {
631 set.acknowledgement = level(inner.u64()?, "acknowledgement")?;
632 }
633 guarantee_key::DURABILITY => {
634 set.durability = Some(level(inner.u64()?, "durability")?);
635 }
636 guarantee_key::REPLICAS => set.replicas = Some(inner.u64()?),
637 guarantee_key::ORDERING => set.ordering = level(inner.u64()?, "ordering")?,
638 guarantee_key::DEDUPLICATION => {
639 set.deduplication = level(inner.u64()?, "deduplication")?;
640 }
641 guarantee_key::DEDUP_WINDOW_MS => set.dedup_window_ms = Some(inner.u64()?),
642 guarantee_key::BACKPRESSURE => {
643 set.backpressure = level(inner.u64()?, "backpressure")?;
644 }
645 guarantee_key::PRODUCER_NAMING => {
646 set.producer_naming = level(inner.u64()?, "producer naming")?;
647 }
648 guarantee_key::CONTROL_ISOLATED => {
649 set.control_isolated = match inner.u64()? {
650 0 => false,
651 1 => true,
652 _ => {
653 return Err(HeaderError::InvalidGuarantees(
654 "control_isolated is 0 or 1",
655 ));
656 }
657 };
658 }
659 _ => inner.skip()?,
660 }
661 }
662 set.validate()?;
663 Ok(set)
664 }
665
666 pub fn intersect(&self, other: &GuaranteeSet) -> Result<GuaranteeSet, &'static str> {
675 if self.backpressure != other.backpressure {
676 return Err("backpressure");
677 }
678 if self.producer_naming != other.producer_naming {
679 return Err("producer naming");
680 }
681 if self.durability.is_some()
682 && other.durability.is_some()
683 && self.durability != other.durability
684 {
685 return Err("durability");
686 }
687 if self.replicas.is_some() && other.replicas.is_some() && self.replicas != other.replicas {
688 return Err("replicas");
689 }
690
691 let acknowledgement = self.acknowledgement.min(other.acknowledgement);
692 let keeps_durability = matches!(
693 acknowledgement,
694 Acknowledgement::Stored | Acknowledgement::Replicated
695 );
696 let deduplication = self.deduplication.min(other.deduplication);
697 let mut merged = GuaranteeSet {
698 delivery: self.delivery.min(other.delivery),
699 acknowledgement,
700 durability: keeps_durability
704 .then_some(self.durability.or(other.durability))
705 .flatten(),
706 replicas: (acknowledgement == Acknowledgement::Replicated)
707 .then_some(self.replicas.or(other.replicas))
708 .flatten(),
709 ordering: self.ordering.min(other.ordering),
710 deduplication,
711 dedup_window_ms: None,
713 backpressure: self.backpressure,
714 producer_naming: self.producer_naming,
715 control_isolated: self.control_isolated && other.control_isolated,
716 };
717 if deduplication == Deduplication::Bounded {
718 merged.dedup_window_ms = match (self.dedup_window_ms, other.dedup_window_ms) {
719 (Some(a), Some(b)) => Some(a.min(b)),
720 (Some(a), None) | (None, Some(a)) => Some(a),
721 (None, None) => None,
722 };
723 }
724 Ok(merged)
725 }
726
727 pub fn reaches(&self, required: &GuaranteeSet) -> bool {
733 if self.delivery < required.delivery
734 || self.acknowledgement < required.acknowledgement
735 || self.ordering < required.ordering
736 || self.deduplication < required.deduplication
737 {
738 return false;
739 }
740 if self.backpressure != required.backpressure
741 || self.producer_naming != required.producer_naming
742 {
743 return false;
744 }
745 if !self.control_isolated && required.control_isolated {
746 return false;
747 }
748 match (self.durability, required.durability) {
749 (_, None) => {}
750 (Some(have), Some(want)) if have >= want => {}
751 _ => return false,
752 }
753 match (self.replicas, required.replicas) {
754 (_, None) => {}
755 (Some(have), Some(want)) if have >= want => {}
756 _ => return false,
757 }
758 match (self.dedup_window_ms, required.dedup_window_ms) {
759 (_, None) => {}
760 (Some(have), Some(want)) if have >= want => {}
761 _ => return false,
762 }
763 true
764 }
765}
766
767fn level<T: WireLevel>(value: u64, dimension: &'static str) -> Result<T, HeaderError> {
769 T::from_wire_value(value).ok_or(HeaderError::UnknownLevel { dimension, value })
770}
771
772trait WireLevel: Sized {
774 fn from_wire_value(value: u64) -> Option<Self>;
775}
776
777macro_rules! impl_wire_level {
778 ($($name:ident),+ $(,)?) => {
779 $(impl WireLevel for $name {
780 fn from_wire_value(value: u64) -> Option<$name> {
781 $name::from_wire(value)
782 }
783 })+
784 };
785}
786
787impl_wire_level!(
788 Delivery,
789 Acknowledgement,
790 Durability,
791 OrderingMode,
792 Deduplication,
793 Backpressure,
794 ProducerNaming,
795 ReportMode,
796);
797
798#[derive(Clone, Debug, PartialEq, Eq)]
800pub enum HeaderError {
801 Malformed(&'static str),
803 Indefinite,
805 DuplicateKey(u64),
807 UnorderedKey(u64),
809 NonUintKey,
811 MissingKey(u64),
813 StringTooLong {
815 key: u64,
817 len: usize,
819 max: usize,
821 },
822 ListTooLong {
824 key: u64,
826 len: u64,
828 max: usize,
830 },
831 DepthExceeded,
833 TrailingBytes,
835 UnknownLevel {
838 dimension: &'static str,
840 value: u64,
842 },
843 InvalidGuarantees(&'static str),
846 InvalidFilter(&'static str),
848 InvalidReport(&'static str),
852}
853
854impl std::fmt::Display for HeaderError {
855 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
856 match self {
857 HeaderError::Malformed(what) => write!(f, "malformed header: {what}"),
858 HeaderError::Indefinite => f.write_str("indefinite-length items are not allowed"),
859 HeaderError::DuplicateKey(k) => write!(f, "duplicate header key {k}"),
860 HeaderError::UnorderedKey(k) => {
861 write!(f, "header key {k} is out of ascending order")
862 }
863 HeaderError::NonUintKey => f.write_str("header key is not an unsigned integer"),
864 HeaderError::MissingKey(k) => write!(f, "required header key {k} is missing"),
865 HeaderError::StringTooLong { key, len, max } => {
866 write!(
867 f,
868 "key {key}: text of {len} bytes exceeds the {max} byte cap"
869 )
870 }
871 HeaderError::ListTooLong { key, len, max } => {
872 write!(
873 f,
874 "key {key}: list of {len} items exceeds the {max} item cap"
875 )
876 }
877 HeaderError::DepthExceeded => f.write_str("unknown field nested too deeply"),
878 HeaderError::TrailingBytes => f.write_str("trailing bytes after the header"),
879 HeaderError::UnknownLevel { dimension, value } => {
880 write!(f, "unknown {dimension} level {value}")
881 }
882 HeaderError::InvalidGuarantees(why) => write!(f, "invalid guarantee set: {why}"),
883 HeaderError::InvalidFilter(why) => write!(f, "invalid topic filter: {why}"),
884 HeaderError::InvalidReport(reason) => write!(f, "invalid report: {reason}"),
885 }
886 }
887}
888
889impl std::error::Error for HeaderError {}
890
891impl From<HeaderError> for Error {
892 fn from(e: HeaderError) -> Error {
893 Error::Protocol(e.to_string())
894 }
895}
896
897fn encode_into_with(
905 out: &mut Vec<u8>,
906 f: impl FnOnce(&mut Encoder<Vec<u8>>) -> Result<(), minicbor::encode::Error<Infallible>>,
907) {
908 let mut e = Encoder::new(std::mem::take(out));
912 f(&mut e).expect("encoding into a Vec is infallible");
913 *out = e.into_writer();
914}
915
916fn skip_value(d: &mut Decoder<'_>, max_depth: usize) -> Result<(), HeaderError> {
923 let mut stack: Vec<u64> = Vec::new();
926 let mut remaining: u64 = 1;
927
928 loop {
929 if remaining == 0 {
930 match stack.pop() {
931 Some(outer) => {
932 remaining = outer;
933 continue;
934 }
935 None => return Ok(()),
936 }
937 }
938 remaining -= 1;
939
940 let ty = d
941 .datatype()
942 .map_err(|_| HeaderError::Malformed("truncated value"))?;
943 let nested = match ty {
944 Type::Bool => {
945 d.bool().map_err(|_| HeaderError::Malformed("bool"))?;
946 None
947 }
948 Type::Null => {
949 d.null().map_err(|_| HeaderError::Malformed("null"))?;
950 None
951 }
952 Type::Undefined => {
953 d.undefined()
954 .map_err(|_| HeaderError::Malformed("undefined"))?;
955 None
956 }
957 Type::U8
958 | Type::U16
959 | Type::U32
960 | Type::U64
961 | Type::I8
962 | Type::I16
963 | Type::I32
964 | Type::I64
965 | Type::Int => {
966 d.int().map_err(|_| HeaderError::Malformed("integer"))?;
967 None
968 }
969 Type::F32 | Type::F64 => {
970 d.f64().map_err(|_| HeaderError::Malformed("float"))?;
971 None
972 }
973 Type::Bytes => {
974 d.bytes()
975 .map_err(|_| HeaderError::Malformed("byte string"))?;
976 None
977 }
978 Type::String => {
979 d.str().map_err(|_| HeaderError::Malformed("text string"))?;
980 None
981 }
982 Type::Array => Some(
983 d.array()
984 .map_err(|_| HeaderError::Malformed("array"))?
985 .ok_or(HeaderError::Indefinite)?,
986 ),
987 Type::Map => {
988 let pairs = d
989 .map()
990 .map_err(|_| HeaderError::Malformed("map"))?
991 .ok_or(HeaderError::Indefinite)?;
992 Some(
993 pairs
994 .checked_mul(2)
995 .ok_or(HeaderError::Malformed("map length overflow"))?,
996 )
997 }
998 Type::BytesIndef | Type::StringIndef | Type::ArrayIndef | Type::MapIndef => {
999 return Err(HeaderError::Indefinite);
1000 }
1001 Type::Break => return Err(HeaderError::Malformed("unexpected break")),
1002 Type::Tag => return Err(HeaderError::Malformed("tags are not allowed")),
1005 Type::F16 => return Err(HeaderError::Malformed("half floats are not allowed")),
1006 Type::Simple => return Err(HeaderError::Malformed("simple values are not allowed")),
1007 Type::Unknown(_) => return Err(HeaderError::Malformed("unknown major type")),
1008 };
1009
1010 if let Some(count) = nested
1011 && count > 0
1012 {
1013 if stack.len() >= max_depth {
1014 return Err(HeaderError::DepthExceeded);
1015 }
1016 stack.push(remaining);
1017 remaining = count;
1018 }
1019 }
1020}
1021
1022struct MapReader<'a, 'b> {
1024 d: &'a mut Decoder<'b>,
1025 remaining: u64,
1026 seen: u64,
1029 last: Option<u64>,
1036}
1037
1038impl<'a, 'b> MapReader<'a, 'b> {
1039 fn new(d: &'a mut Decoder<'b>) -> Result<MapReader<'a, 'b>, HeaderError> {
1040 let len = d
1041 .map()
1042 .map_err(|_| HeaderError::Malformed("header is not a map"))?
1043 .ok_or(HeaderError::Indefinite)?;
1044 Ok(MapReader {
1045 d,
1046 remaining: len,
1047 seen: 0,
1048 last: None,
1049 })
1050 }
1051
1052 fn next_key(&mut self) -> Result<Option<u64>, HeaderError> {
1053 if self.remaining == 0 {
1054 return Ok(None);
1055 }
1056 self.remaining -= 1;
1057 match self.d.datatype() {
1058 Ok(Type::U8 | Type::U16 | Type::U32 | Type::U64) => {}
1059 Ok(_) => return Err(HeaderError::NonUintKey),
1060 Err(_) => return Err(HeaderError::Malformed("truncated key")),
1061 }
1062 let key = self.d.u64().map_err(|_| HeaderError::NonUintKey)?;
1063 if let Some(prev) = self.last {
1064 if key == prev {
1065 return Err(HeaderError::DuplicateKey(key));
1066 }
1067 if key < prev {
1068 return Err(HeaderError::UnorderedKey(key));
1069 }
1070 }
1071 self.last = Some(key);
1072 if key < 64 {
1073 self.seen |= 1u64 << key;
1074 }
1075 Ok(Some(key))
1076 }
1077
1078 fn saw(&self, key: u64) -> bool {
1079 key < 64 && self.seen & (1u64 << key) != 0
1080 }
1081
1082 fn require(&self, key: u64) -> Result<(), HeaderError> {
1083 if self.saw(key) {
1084 Ok(())
1085 } else {
1086 Err(HeaderError::MissingKey(key))
1087 }
1088 }
1089
1090 fn u64(&mut self) -> Result<u64, HeaderError> {
1091 self.d
1092 .u64()
1093 .map_err(|_| HeaderError::Malformed("expected an unsigned integer"))
1094 }
1095
1096 fn text(&mut self, key: u64, max: usize) -> Result<String, HeaderError> {
1097 let s = self
1098 .d
1099 .str()
1100 .map_err(|_| HeaderError::Malformed("expected a text string"))?;
1101 if s.len() > max {
1102 return Err(HeaderError::StringTooLong {
1103 key,
1104 len: s.len(),
1105 max,
1106 });
1107 }
1108 Ok(s.to_owned())
1109 }
1110
1111 fn byte_array<const N: usize>(&mut self, key: u64) -> Result<[u8; N], HeaderError> {
1118 let bytes = self
1119 .d
1120 .bytes()
1121 .map_err(|_| HeaderError::Malformed("expected a byte string"))?;
1122 if bytes.len() > N {
1123 return Err(HeaderError::StringTooLong {
1124 key,
1125 len: bytes.len(),
1126 max: N,
1127 });
1128 }
1129 bytes
1130 .try_into()
1131 .map_err(|_| HeaderError::Malformed("byte string has the wrong length"))
1132 }
1133
1134 fn uint_list(&mut self, key: u64) -> Result<Vec<u64>, HeaderError> {
1135 let len = self
1136 .d
1137 .array()
1138 .map_err(|_| HeaderError::Malformed("expected an array"))?
1139 .ok_or(HeaderError::Indefinite)?;
1140 if len > limits::MAX_LIST_ITEMS as u64 {
1141 return Err(HeaderError::ListTooLong {
1142 key,
1143 len,
1144 max: limits::MAX_LIST_ITEMS,
1145 });
1146 }
1147 let mut out = Vec::with_capacity(len as usize);
1149 for _ in 0..len {
1150 out.push(self.u64()?);
1151 }
1152 Ok(out)
1153 }
1154
1155 fn report_levels(&mut self) -> Result<Vec<CursorLevel>, HeaderError> {
1163 let len = self
1164 .d
1165 .array()
1166 .map_err(|_| HeaderError::Malformed("expected an array"))?
1167 .ok_or(HeaderError::Indefinite)?;
1168 if len > limits::MAX_REPORT_LEVELS as u64 {
1169 return Err(HeaderError::InvalidReport("too many report levels"));
1170 }
1171 let mut out: Vec<CursorLevel> = Vec::with_capacity(len as usize);
1173 let mut last: Option<u64> = None;
1174 for _ in 0..len {
1175 let value = self.u64()?;
1176 if let Some(prev) = last
1177 && value <= prev
1178 {
1179 return Err(HeaderError::InvalidReport("report levels must ascend"));
1180 }
1181 last = Some(value);
1182 out.push(
1183 CursorLevel::from_wire(value).ok_or(HeaderError::UnknownLevel {
1184 dimension: "report",
1185 value,
1186 })?,
1187 );
1188 }
1189 Ok(out)
1190 }
1191
1192 fn skip(&mut self) -> Result<(), HeaderError> {
1193 skip_value(self.d, limits::MAX_SKIP_DEPTH)
1194 }
1195}
1196
1197fn finish(d: &Decoder<'_>) -> Result<(), HeaderError> {
1199 if d.position() == d.input().len() {
1200 Ok(())
1201 } else {
1202 Err(HeaderError::TrailingBytes)
1203 }
1204}
1205
1206#[derive(Clone, Debug, PartialEq, Eq)]
1208pub struct Hello {
1209 pub versions: Vec<u64>,
1211 pub max_header_bytes: u64,
1213 pub max_transfers: u64,
1215 pub capabilities: Vec<u64>,
1217 pub required_capabilities: Vec<u64>,
1219 pub guarantees_offered: Option<GuaranteeSet>,
1225 pub guarantees_required: Option<GuaranteeSet>,
1231}
1232
1233impl Hello {
1234 pub fn v0(max_header_bytes: u64, max_transfers: u64) -> Hello {
1237 Hello {
1238 versions: vec![crate::VERSION],
1239 max_header_bytes,
1240 max_transfers,
1241 capabilities: Vec::new(),
1242 required_capabilities: Vec::new(),
1243 guarantees_offered: None,
1244 guarantees_required: None,
1245 }
1246 }
1247
1248 pub fn offered(&self) -> GuaranteeSet {
1250 self.guarantees_offered.unwrap_or(GuaranteeSet::CORE)
1251 }
1252
1253 pub fn required(&self) -> GuaranteeSet {
1255 self.guarantees_required.unwrap_or(GuaranteeSet::CORE)
1256 }
1257
1258 pub fn encode(&self) -> Vec<u8> {
1260 let mut out = Vec::new();
1261 self.encode_into(&mut out);
1262 out
1263 }
1264
1265 pub fn encode_into(&self, out: &mut Vec<u8>) {
1269 encode_into_with(out, |e| {
1270 let offered = self.guarantees_offered.filter(|s| !s.is_core());
1273 let required = self.guarantees_required.filter(|s| !s.is_core());
1274 e.map(5 + u64::from(offered.is_some()) + u64::from(required.is_some()))?;
1275 e.u64(hello_key::VERSIONS)?
1276 .array(self.versions.len() as u64)?;
1277 for v in &self.versions {
1278 e.u64(*v)?;
1279 }
1280 e.u64(hello_key::MAX_HEADER_BYTES)?
1281 .u64(self.max_header_bytes)?;
1282 e.u64(hello_key::MAX_TRANSFERS)?.u64(self.max_transfers)?;
1283 e.u64(hello_key::CAPABILITIES)?
1284 .array(self.capabilities.len() as u64)?;
1285 for c in &self.capabilities {
1286 e.u64(*c)?;
1287 }
1288 e.u64(hello_key::REQUIRED_CAPABILITIES)?
1289 .array(self.required_capabilities.len() as u64)?;
1290 for c in &self.required_capabilities {
1291 e.u64(*c)?;
1292 }
1293 if let Some(set) = offered {
1294 e.u64(hello_key::GUARANTEES_OFFERED)?;
1295 set.encode_into(e)?;
1296 }
1297 if let Some(set) = required {
1298 e.u64(hello_key::GUARANTEES_REQUIRED)?;
1299 set.encode_into(e)?;
1300 }
1301 Ok(())
1302 })
1303 }
1304
1305 pub fn decode(bytes: &[u8]) -> Result<Hello, HeaderError> {
1307 let mut d = Decoder::new(bytes);
1308 let mut versions = Vec::new();
1309 let mut max_header_bytes = 0;
1310 let mut max_transfers = 0;
1311 let mut capabilities = Vec::new();
1312 let mut required_capabilities = Vec::new();
1313 let mut guarantees_offered = None;
1314 let mut guarantees_required = None;
1315 {
1316 let mut m = MapReader::new(&mut d)?;
1317 while let Some(key) = m.next_key()? {
1318 match key {
1319 hello_key::VERSIONS => versions = m.uint_list(key)?,
1320 hello_key::MAX_HEADER_BYTES => max_header_bytes = m.u64()?,
1321 hello_key::MAX_TRANSFERS => max_transfers = m.u64()?,
1322 hello_key::CAPABILITIES => capabilities = m.uint_list(key)?,
1323 hello_key::REQUIRED_CAPABILITIES => required_capabilities = m.uint_list(key)?,
1324 hello_key::GUARANTEES_OFFERED => {
1325 guarantees_offered = Some(GuaranteeSet::decode_from(&mut m)?);
1326 }
1327 hello_key::GUARANTEES_REQUIRED => {
1328 guarantees_required = Some(GuaranteeSet::decode_from(&mut m)?);
1329 }
1330 _ => m.skip()?,
1331 }
1332 }
1333 for key in [
1334 hello_key::VERSIONS,
1335 hello_key::MAX_HEADER_BYTES,
1336 hello_key::MAX_TRANSFERS,
1337 hello_key::CAPABILITIES,
1338 hello_key::REQUIRED_CAPABILITIES,
1339 ] {
1340 m.require(key)?;
1341 }
1342 }
1343 finish(&d)?;
1344 let hello = Hello {
1345 versions,
1346 max_header_bytes,
1347 max_transfers,
1348 capabilities,
1349 required_capabilities,
1350 guarantees_offered,
1351 guarantees_required,
1352 };
1353 if !hello.offered().reaches(&hello.required()) {
1356 return Err(HeaderError::InvalidGuarantees(
1357 "guarantees_required is not covered by guarantees_offered",
1358 ));
1359 }
1360 Ok(hello)
1361 }
1362}
1363
1364#[derive(Clone, Debug, Default, PartialEq, Eq)]
1371pub struct DataHeader {
1372 pub endpoint: Option<String>,
1374 pub content_len: Option<u64>,
1376 pub content_type: Option<String>,
1378 pub traceparent: Option<String>,
1380 pub tracestate: Option<String>,
1382 pub topic: Option<String>,
1386 pub sequence: Option<u64>,
1395 pub producer: Option<[u8; limits::PRODUCER_BYTES]>,
1406 pub achieved: Option<Acknowledgement>,
1428 pub report_id: Option<u64>,
1435 pub report: Vec<CursorLevel>,
1444 pub report_mode: ReportMode,
1448}
1449
1450impl DataHeader {
1451 pub fn addressed(endpoint: impl Into<String>) -> DataHeader {
1453 DataHeader {
1454 endpoint: Some(endpoint.into()),
1455 ..DataHeader::default()
1456 }
1457 }
1458
1459 pub fn reply() -> DataHeader {
1464 DataHeader::default()
1465 }
1466
1467 pub fn encode(&self) -> Vec<u8> {
1484 let mut out = Vec::new();
1485 self.encode_into(&mut out);
1486 out
1487 }
1488
1489 pub fn encode_into(&self, out: &mut Vec<u8>) {
1493 let mut report: Vec<u64> = self.report.iter().map(|level| level.to_wire()).collect();
1496 report.sort_unstable();
1497 report.dedup();
1498 let count = u64::from(self.endpoint.is_some())
1499 + u64::from(self.content_len.is_some())
1500 + u64::from(self.content_type.is_some())
1501 + u64::from(self.traceparent.is_some())
1502 + u64::from(self.tracestate.is_some())
1503 + u64::from(self.topic.is_some())
1504 + u64::from(self.sequence.is_some())
1505 + u64::from(self.producer.is_some())
1506 + u64::from(self.achieved.is_some())
1507 + u64::from(self.report_id.is_some())
1508 + u64::from(!report.is_empty())
1509 + u64::from(self.report_mode != ReportMode::default());
1510 encode_into_with(out, |e| {
1511 e.map(count)?;
1512 if let Some(endpoint) = &self.endpoint {
1513 e.u64(data_key::ENDPOINT)?.str(endpoint)?;
1514 }
1515 if let Some(len) = self.content_len {
1516 e.u64(data_key::CONTENT_LEN)?.u64(len)?;
1517 }
1518 if let Some(ct) = &self.content_type {
1519 e.u64(data_key::CONTENT_TYPE)?.str(ct)?;
1520 }
1521 if let Some(tp) = &self.traceparent {
1522 e.u64(data_key::TRACEPARENT)?.str(tp)?;
1523 }
1524 if let Some(ts) = &self.tracestate {
1525 e.u64(data_key::TRACESTATE)?.str(ts)?;
1526 }
1527 if let Some(topic) = &self.topic {
1528 e.u64(data_key::TOPIC)?.str(topic)?;
1529 }
1530 if let Some(sequence) = self.sequence {
1533 e.u64(data_key::SEQUENCE)?.u64(sequence)?;
1534 }
1535 if let Some(producer) = &self.producer {
1536 e.u64(data_key::PRODUCER)?.bytes(producer)?;
1537 }
1538 if let Some(achieved) = self.achieved {
1539 e.u64(data_key::ACHIEVED)?.u64(achieved.to_wire())?;
1540 }
1541 if let Some(report_id) = self.report_id {
1542 e.u64(data_key::REPORT_ID)?.u64(report_id)?;
1543 }
1544 if !report.is_empty() {
1545 e.u64(data_key::REPORT)?.array(report.len() as u64)?;
1546 for value in &report {
1547 e.u64(*value)?;
1548 }
1549 }
1550 if self.report_mode != ReportMode::default() {
1554 e.u64(data_key::REPORT_MODE)?
1555 .u64(self.report_mode.to_wire())?;
1556 }
1557 Ok(())
1558 })
1559 }
1560
1561 pub fn decode(bytes: &[u8]) -> Result<DataHeader, HeaderError> {
1563 let mut d = Decoder::new(bytes);
1564 let mut header = DataHeader::default();
1565 {
1566 let mut m = MapReader::new(&mut d)?;
1567 while let Some(key) = m.next_key()? {
1568 match key {
1569 data_key::ENDPOINT => {
1570 header.endpoint = Some(m.text(key, limits::MAX_ENDPOINT_BYTES)?)
1571 }
1572 data_key::CONTENT_LEN => header.content_len = Some(m.u64()?),
1573 data_key::CONTENT_TYPE => {
1574 header.content_type = Some(m.text(key, limits::MAX_CONTENT_TYPE_BYTES)?)
1575 }
1576 data_key::TRACEPARENT => {
1577 header.traceparent = Some(m.text(key, limits::MAX_TRACEPARENT_BYTES)?)
1578 }
1579 data_key::TRACESTATE => {
1580 header.tracestate = Some(m.text(key, limits::MAX_TRACESTATE_BYTES)?)
1581 }
1582 data_key::TOPIC => header.topic = Some(m.text(key, limits::MAX_TOPIC_BYTES)?),
1583 data_key::SEQUENCE => header.sequence = Some(m.u64()?),
1584 data_key::PRODUCER => header.producer = Some(m.byte_array(key)?),
1585 data_key::ACHIEVED => {
1590 let value = m.u64()?;
1591 header.achieved = Some(Acknowledgement::from_wire(value).ok_or(
1592 HeaderError::UnknownLevel {
1593 dimension: "achieved",
1594 value,
1595 },
1596 )?);
1597 }
1598 data_key::REPORT_ID => header.report_id = Some(m.u64()?),
1599 data_key::REPORT => header.report = m.report_levels()?,
1600 data_key::REPORT_MODE => {
1601 header.report_mode = level(m.u64()?, "report_mode")?;
1602 }
1603 _ => m.skip()?,
1604 }
1605 }
1606 }
1607 finish(&d)?;
1608 if !header.report.is_empty() && header.report_id.is_none() {
1612 return Err(HeaderError::InvalidReport("report without report_id"));
1613 }
1614 if header.report_id.is_some() && header.report.is_empty() {
1615 return Err(HeaderError::InvalidReport("report_id without report"));
1616 }
1617 Ok(header)
1618 }
1619}
1620
1621#[derive(Clone, Debug, PartialEq, Eq)]
1626pub struct ErrorHeader {
1627 pub code: u64,
1629 pub message: Option<String>,
1631}
1632
1633impl ErrorHeader {
1634 pub fn new(code: weida_core::ErrorCode) -> ErrorHeader {
1636 ErrorHeader {
1637 code: code.to_wire(),
1638 message: None,
1639 }
1640 }
1641
1642 pub fn error_code(&self) -> Option<weida_core::ErrorCode> {
1644 weida_core::ErrorCode::from_wire(self.code)
1645 }
1646
1647 pub fn encode(&self) -> Vec<u8> {
1649 let mut out = Vec::new();
1650 self.encode_into(&mut out);
1651 out
1652 }
1653
1654 pub fn encode_into(&self, out: &mut Vec<u8>) {
1658 let count = 1 + u64::from(self.message.is_some());
1659 encode_into_with(out, |e| {
1660 e.map(count)?;
1661 e.u64(error_key::CODE)?.u64(self.code)?;
1662 if let Some(msg) = &self.message {
1663 e.u64(error_key::MESSAGE)?.str(msg)?;
1664 }
1665 Ok(())
1666 })
1667 }
1668
1669 pub fn decode(bytes: &[u8]) -> Result<ErrorHeader, HeaderError> {
1671 let mut d = Decoder::new(bytes);
1672 let mut code = 0;
1673 let mut message = None;
1674 {
1675 let mut m = MapReader::new(&mut d)?;
1676 while let Some(key) = m.next_key()? {
1677 match key {
1678 error_key::CODE => code = m.u64()?,
1679 error_key::MESSAGE => message = Some(m.text(key, limits::MAX_MESSAGE_BYTES)?),
1680 _ => m.skip()?,
1681 }
1682 }
1683 m.require(error_key::CODE)?;
1684 }
1685 finish(&d)?;
1686 Ok(ErrorHeader { code, message })
1687 }
1688}
1689
1690#[derive(Clone, Debug, PartialEq, Eq)]
1697pub struct SubscriptionHeader {
1698 pub endpoint: String,
1700 pub filter: String,
1703}
1704
1705impl SubscriptionHeader {
1706 pub fn new(endpoint: impl Into<String>, filter: impl Into<String>) -> SubscriptionHeader {
1708 SubscriptionHeader {
1709 endpoint: endpoint.into(),
1710 filter: filter.into(),
1711 }
1712 }
1713
1714 pub fn encode(&self) -> Vec<u8> {
1716 let mut out = Vec::new();
1717 self.encode_into(&mut out);
1718 out
1719 }
1720
1721 pub fn encode_into(&self, out: &mut Vec<u8>) {
1725 encode_into_with(out, |e| {
1729 e.map(2)?;
1730 e.u64(subscription_key::ENDPOINT)?.str(&self.endpoint)?;
1731 e.u64(subscription_key::FILTER)?.str(&self.filter)?;
1732 Ok(())
1733 })
1734 }
1735
1736 pub fn decode(bytes: &[u8]) -> Result<SubscriptionHeader, HeaderError> {
1738 let mut d = Decoder::new(bytes);
1739 let mut endpoint = None;
1740 let mut filter = None;
1741 {
1742 let mut m = MapReader::new(&mut d)?;
1743 while let Some(key) = m.next_key()? {
1744 match key {
1745 subscription_key::ENDPOINT => {
1746 endpoint = Some(m.text(key, limits::MAX_ENDPOINT_BYTES)?)
1747 }
1748 subscription_key::FILTER => {
1749 filter = Some(m.text(key, limits::MAX_FILTER_BYTES)?)
1750 }
1751 _ => m.skip()?,
1752 }
1753 }
1754 m.require(subscription_key::ENDPOINT)?;
1755 m.require(subscription_key::FILTER)?;
1756 }
1757 let filter = filter.expect("presence checked above");
1762 filter::validate(&filter)?;
1763 finish(&d)?;
1764 Ok(SubscriptionHeader {
1765 endpoint: endpoint.expect("presence checked above"),
1766 filter,
1767 })
1768 }
1769}
1770
1771#[derive(Clone, Debug, PartialEq, Eq)]
1795pub struct CreditHeader {
1796 pub endpoint: String,
1798 pub filter: String,
1801 pub limit: u64,
1804}
1805
1806impl CreditHeader {
1807 pub fn new(endpoint: impl Into<String>, filter: impl Into<String>, limit: u64) -> CreditHeader {
1809 CreditHeader {
1810 endpoint: endpoint.into(),
1811 filter: filter.into(),
1812 limit,
1813 }
1814 }
1815
1816 pub fn encode(&self) -> Vec<u8> {
1818 let mut out = Vec::new();
1819 self.encode_into(&mut out);
1820 out
1821 }
1822
1823 pub fn encode_into(&self, out: &mut Vec<u8>) {
1827 encode_into_with(out, |e| {
1828 e.map(3)?;
1829 e.u64(credit_key::ENDPOINT)?.str(&self.endpoint)?;
1830 e.u64(credit_key::FILTER)?.str(&self.filter)?;
1831 e.u64(credit_key::LIMIT)?.u64(self.limit)?;
1832 Ok(())
1833 })
1834 }
1835
1836 pub fn decode(bytes: &[u8]) -> Result<CreditHeader, HeaderError> {
1838 let mut d = Decoder::new(bytes);
1839 let mut endpoint = None;
1840 let mut filter = None;
1841 let mut limit = None;
1842 {
1843 let mut m = MapReader::new(&mut d)?;
1844 while let Some(key) = m.next_key()? {
1845 match key {
1846 credit_key::ENDPOINT => {
1847 endpoint = Some(m.text(key, limits::MAX_ENDPOINT_BYTES)?)
1848 }
1849 credit_key::FILTER => filter = Some(m.text(key, limits::MAX_FILTER_BYTES)?),
1850 credit_key::LIMIT => limit = Some(m.u64()?),
1851 _ => m.skip()?,
1852 }
1853 }
1854 m.require(credit_key::ENDPOINT)?;
1855 m.require(credit_key::FILTER)?;
1856 m.require(credit_key::LIMIT)?;
1857 }
1858 let filter = filter.expect("presence checked above");
1861 filter::validate(&filter)?;
1862 finish(&d)?;
1863 Ok(CreditHeader {
1864 endpoint: endpoint.expect("presence checked above"),
1865 filter,
1866 limit: limit.expect("presence checked above"),
1867 })
1868 }
1869}
1870
1871#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1879pub struct CursorHeader {
1880 pub report_id: u64,
1882}
1883
1884impl CursorHeader {
1885 pub fn encode(&self) -> Vec<u8> {
1887 let mut out = Vec::new();
1888 self.encode_into(&mut out);
1889 out
1890 }
1891
1892 pub fn encode_into(&self, out: &mut Vec<u8>) {
1896 encode_into_with(out, |e| {
1897 e.map(1)?;
1898 e.u64(cursor_key::REPORT_ID)?.u64(self.report_id)?;
1899 Ok(())
1900 })
1901 }
1902
1903 pub fn decode(bytes: &[u8]) -> Result<CursorHeader, HeaderError> {
1905 let mut d = Decoder::new(bytes);
1906 let mut report_id = None;
1907 {
1908 let mut m = MapReader::new(&mut d)?;
1909 while let Some(key) = m.next_key()? {
1910 match key {
1911 cursor_key::REPORT_ID => report_id = Some(m.u64()?),
1912 _ => m.skip()?,
1913 }
1914 }
1915 m.require(cursor_key::REPORT_ID)?;
1916 }
1917 finish(&d)?;
1918 Ok(CursorHeader {
1919 report_id: report_id.expect("presence checked above"),
1920 })
1921 }
1922}
1923
1924pub const MAX_CURSOR_RECORD_LEN: usize = 2 * crate::varint::MAX_ENCODED_LEN;
1926
1927pub fn encode_cursor_record(
1934 level: CursorLevel,
1935 offset: u64,
1936 out: &mut Vec<u8>,
1937) -> Result<(), VarintError> {
1938 encode_varint(level.to_wire(), out)?;
1939 encode_varint(offset, out)
1940}
1941
1942pub fn decode_cursor_record(
1951 input: &[u8],
1952) -> Result<Option<(CursorLevel, u64, usize)>, HeaderError> {
1953 let Ok((raw_level, level_len)) = decode_varint(input) else {
1956 return Ok(None);
1957 };
1958 let Ok((offset, offset_len)) = decode_varint(&input[level_len..]) else {
1959 return Ok(None);
1960 };
1961 let level = CursorLevel::from_wire(raw_level).ok_or(HeaderError::UnknownLevel {
1962 dimension: "cursor",
1963 value: raw_level,
1964 })?;
1965 Ok(Some((level, offset, level_len + offset_len)))
1966}
1967
1968#[cfg(test)]
1969mod tests {
1970 fn encode_with(
1973 f: impl FnOnce(
1974 &mut minicbor::Encoder<Vec<u8>>,
1975 ) -> Result<(), minicbor::encode::Error<std::convert::Infallible>>,
1976 ) -> Vec<u8> {
1977 let mut out = Vec::new();
1978 super::encode_into_with(&mut out, f);
1979 out
1980 }
1981
1982 use super::*;
1983 use weida_core::ErrorCode;
1984
1985 #[test]
1988 fn golden_data_request_header() {
1989 let h = DataHeader::addressed("/t");
1990 let bytes = h.encode();
1991 assert_eq!(bytes, vec![0xA1, 0x00, 0x62, 0x2F, 0x74]);
1992 assert_eq!(bytes.len(), 0x05);
1993 assert_eq!(DataHeader::decode(&bytes).unwrap(), h);
1994 }
1995
1996 #[test]
1997 fn golden_data_reply_header() {
1998 let h = DataHeader::reply();
2000 let bytes = h.encode();
2001 assert_eq!(bytes, vec![0xA0]);
2002 assert_eq!(bytes.len(), 0x01);
2003 assert_eq!(DataHeader::decode(&bytes).unwrap(), h);
2004 }
2005
2006 #[test]
2007 fn golden_hello_header() {
2008 let h = Hello::v0(16384, 1024);
2009 let bytes = h.encode();
2010 assert_eq!(
2011 bytes,
2012 vec![
2013 0xA5, 0x00, 0x81, 0x00, 0x01, 0x19, 0x40, 0x00, 0x02, 0x19, 0x04, 0x00, 0x03, 0x80,
2014 0x04, 0x80
2015 ]
2016 );
2017 assert_eq!(bytes.len(), 0x10);
2018 assert_eq!(Hello::decode(&bytes).unwrap(), h);
2019 }
2020
2021 #[test]
2022 fn golden_error_header() {
2023 let h = ErrorHeader::new(ErrorCode::NoReply);
2024 let bytes = h.encode();
2025 assert_eq!(bytes, vec![0xA1, 0x00, 0x05]);
2026 assert_eq!(bytes.len(), 0x03);
2027 assert_eq!(ErrorHeader::decode(&bytes).unwrap(), h);
2028 }
2029
2030 #[test]
2031 fn golden_pub_copy_data_header() {
2032 let mut h = DataHeader::addressed("/md");
2033 h.topic = Some("px.eur".into());
2034 let bytes = h.encode();
2035 assert_eq!(
2036 bytes,
2037 vec![
2038 0xA2, 0x00, 0x63, 0x2F, 0x6D, 0x64, 0x05, 0x66, 0x70, 0x78, 0x2E, 0x65, 0x75, 0x72
2039 ]
2040 );
2041 assert_eq!(bytes.len(), 0x0E);
2042 assert_eq!(DataHeader::decode(&bytes).unwrap(), h);
2043 }
2044
2045 const VECTOR_PRODUCER: [u8; limits::PRODUCER_BYTES] = [
2048 0x9F, 0x86, 0xD0, 0x81, 0x88, 0x4C, 0x7D, 0x65, 0x9A, 0x2F, 0xEA, 0xA0, 0xC5, 0x5A, 0xD0,
2049 0x15, 0xA3, 0xBF, 0x4F, 0x1B, 0x2B, 0x0B, 0x82, 0x2C, 0xD1, 0x5D, 0x6C, 0x15, 0xB0, 0xF0,
2050 0x0A, 0x08,
2051 ];
2052
2053 #[test]
2054 fn golden_sequenced_data_header() {
2055 let mut h = DataHeader::addressed("/t");
2056 h.sequence = Some(1);
2057 let bytes = h.encode();
2058 assert_eq!(bytes, vec![0xA2, 0x00, 0x62, 0x2F, 0x74, 0x06, 0x01]);
2059 assert_eq!(bytes.len(), 0x07);
2060 assert_eq!(DataHeader::decode(&bytes).unwrap(), h);
2061 }
2062
2063 #[test]
2064 fn golden_relayed_data_header() {
2065 let mut h = DataHeader::addressed("/t");
2066 h.sequence = Some(1);
2067 h.producer = Some(VECTOR_PRODUCER);
2068 let bytes = h.encode();
2069 let mut expected = vec![0xA3, 0x00, 0x62, 0x2F, 0x74, 0x06, 0x01, 0x07, 0x58, 0x20];
2070 expected.extend_from_slice(&VECTOR_PRODUCER);
2071 assert_eq!(bytes, expected);
2072 assert_eq!(bytes.len(), 0x2A);
2073 assert_eq!(DataHeader::decode(&bytes).unwrap(), h);
2074 }
2075
2076 #[test]
2077 fn a_producer_longer_than_the_cap_is_rejected() {
2078 let bytes = encode_with(|e| {
2079 e.map(1)?;
2080 e.u64(data_key::PRODUCER)?
2081 .bytes(&[0u8; limits::PRODUCER_BYTES + 1])?;
2082 Ok(())
2083 });
2084 assert_eq!(
2085 DataHeader::decode(&bytes),
2086 Err(HeaderError::StringTooLong {
2087 key: data_key::PRODUCER,
2088 len: limits::PRODUCER_BYTES + 1,
2089 max: limits::PRODUCER_BYTES,
2090 })
2091 );
2092 }
2093
2094 #[test]
2095 fn a_producer_shorter_than_a_digest_is_rejected() {
2096 let bytes = encode_with(|e| {
2099 e.map(1)?;
2100 e.u64(data_key::PRODUCER)?.bytes(&[0u8; 16])?;
2101 Ok(())
2102 });
2103 assert!(matches!(
2104 DataHeader::decode(&bytes),
2105 Err(HeaderError::Malformed(_))
2106 ));
2107 }
2108
2109 #[test]
2110 fn the_new_keys_reject_the_wrong_cbor_type() {
2111 let sequence_as_text = encode_with(|e| {
2112 e.map(1)?;
2113 e.u64(data_key::SEQUENCE)?.str("7")?;
2114 Ok(())
2115 });
2116 assert!(DataHeader::decode(&sequence_as_text).is_err());
2117
2118 let producer_as_text = encode_with(|e| {
2119 e.map(1)?;
2120 e.u64(data_key::PRODUCER)?.str("sha256:…")?;
2121 Ok(())
2122 });
2123 assert!(DataHeader::decode(&producer_as_text).is_err());
2124 }
2125
2126 #[test]
2127 fn a_v0_header_carries_neither_new_key() {
2128 let mut h = DataHeader::addressed("/t");
2132 h.traceparent = Some("00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01".into());
2133 let bytes = h.encode();
2134 let mut d = Decoder::new(&bytes);
2135 let pairs = d.map().unwrap().unwrap();
2136 let keys: Vec<u64> = (0..pairs)
2137 .map(|_| {
2138 let key = d.u64().unwrap();
2139 d.skip().unwrap();
2140 key
2141 })
2142 .collect();
2143 assert_eq!(keys, vec![data_key::ENDPOINT, data_key::TRACEPARENT]);
2144 }
2145
2146 #[test]
2147 fn golden_subscription_headers() {
2148 let h = SubscriptionHeader::new("/md", "px.");
2149 let bytes = h.encode();
2150 assert_eq!(
2151 bytes,
2152 vec![
2153 0xA2, 0x00, 0x63, 0x2F, 0x6D, 0x64, 0x01, 0x63, 0x70, 0x78, 0x2E
2154 ]
2155 );
2156 assert_eq!(bytes.len(), 0x0B);
2157 assert_eq!(SubscriptionHeader::decode(&bytes).unwrap(), h);
2160 }
2161
2162 #[test]
2165 fn data_header_roundtrip_with_every_field() {
2166 let h = DataHeader {
2167 endpoint: Some("/transform".into()),
2168 content_len: Some(1 << 40),
2169 content_type: Some("application/octet-stream".into()),
2170 traceparent: Some("00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01".into()),
2171 tracestate: Some("vendor=value".into()),
2172 topic: Some("px.eur".into()),
2173 sequence: Some(u64::MAX),
2174 producer: Some([0x5A; limits::PRODUCER_BYTES]),
2175 achieved: Some(Acknowledgement::Processed),
2176 report_id: Some(7),
2177 report: vec![
2178 CursorLevel::Known(Acknowledgement::Accepted),
2179 CursorLevel::Known(Acknowledgement::Processed),
2180 CursorLevel::Application(CursorLevel::APPLICATION_FLOOR),
2181 ],
2182 report_mode: ReportMode::FinalOnly,
2183 };
2184 assert_eq!(DataHeader::decode(&h.encode()).unwrap(), h);
2185 }
2186
2187 #[test]
2188 fn error_header_roundtrip_with_and_without_message() {
2189 let bare = ErrorHeader::new(ErrorCode::UnknownEndpoint);
2190 assert_eq!(ErrorHeader::decode(&bare.encode()).unwrap(), bare);
2191 assert_eq!(bare.error_code(), Some(ErrorCode::UnknownEndpoint));
2192
2193 let with_msg = ErrorHeader {
2194 code: 4,
2195 message: Some("handler panicked".into()),
2196 };
2197 assert_eq!(ErrorHeader::decode(&with_msg.encode()).unwrap(), with_msg);
2198 }
2199
2200 #[test]
2201 fn keys_are_emitted_in_ascending_order() {
2202 let h = DataHeader {
2203 endpoint: Some("/x".into()),
2204 content_len: Some(1),
2205 content_type: Some("t".into()),
2206 traceparent: Some("p".into()),
2207 tracestate: Some("s".into()),
2208 topic: Some("k".into()),
2209 sequence: Some(9),
2210 producer: Some([0u8; limits::PRODUCER_BYTES]),
2211 achieved: Some(Acknowledgement::Accepted),
2212 report_id: Some(1),
2213 report: vec![CursorLevel::Known(Acknowledgement::Stored)],
2214 report_mode: ReportMode::FinalOnly,
2215 };
2216 let bytes = h.encode();
2217 let mut d = Decoder::new(&bytes);
2218 let n = d.map().unwrap().unwrap();
2219 let mut last = None;
2220 for _ in 0..n {
2221 let key = d.u64().unwrap();
2222 if let Some(prev) = last {
2223 assert!(key > prev, "keys must ascend: {prev} then {key}");
2224 }
2225 last = Some(key);
2226 d.skip().unwrap();
2227 }
2228 }
2229
2230 #[test]
2231 fn an_unsorted_report_with_repeats_is_emitted_as_the_canonical_ascending_set() {
2232 let h = DataHeader {
2237 report_id: Some(1),
2238 report: vec![
2239 CursorLevel::Application(CursorLevel::APPLICATION_FLOOR),
2240 CursorLevel::Known(Acknowledgement::Stored),
2241 CursorLevel::Application(CursorLevel::APPLICATION_FLOOR),
2242 CursorLevel::Known(Acknowledgement::Accepted),
2243 CursorLevel::Known(Acknowledgement::Stored),
2244 ],
2245 ..DataHeader::reply()
2246 };
2247 let decoded = DataHeader::decode(&h.encode()).expect("encoder emits the canonical form");
2248 assert_eq!(
2249 decoded.report,
2250 vec![
2251 CursorLevel::Known(Acknowledgement::Accepted),
2252 CursorLevel::Known(Acknowledgement::Stored),
2253 CursorLevel::Application(CursorLevel::APPLICATION_FLOOR),
2254 ]
2255 );
2256 }
2257
2258 #[test]
2261 fn every_data_field_is_optional_at_the_decoder() {
2262 assert_eq!(DataHeader::decode(&[0xA0]).unwrap(), DataHeader::default());
2266
2267 let only_topic = encode_with(|e| {
2268 e.map(1)?;
2269 e.u64(data_key::TOPIC)?.str("px.eur")?;
2270 Ok(())
2271 });
2272 let h = DataHeader::decode(&only_topic).unwrap();
2273 assert_eq!(h.topic.as_deref(), Some("px.eur"));
2274 assert_eq!(h.endpoint, None);
2275 }
2276
2277 #[test]
2278 fn absent_fields_are_omitted_by_the_encoder() {
2279 let h = DataHeader::addressed("/t");
2280 assert_eq!(h.encode(), vec![0xA1, 0x00, 0x62, 0x2F, 0x74]);
2281 }
2282
2283 #[test]
2286 fn unknown_keys_are_skipped() {
2287 let h = DataHeader::addressed("/t");
2290 let extended = encode_with(|e| {
2291 e.map(2)?;
2292 e.u64(0)?.str("/t")?;
2293 e.u64(63)?.array(2)?.u64(7)?.map(1)?.u64(1)?.bool(true)?;
2294 Ok(())
2295 });
2296 assert_eq!(DataHeader::decode(&extended).unwrap(), h);
2297 }
2298
2299 #[test]
2300 fn unknown_keys_above_the_reserved_range_are_skipped() {
2301 let extended = encode_with(|e| {
2302 e.map(2)?;
2303 e.u64(1)?.u64(5)?;
2304 e.u64(1000)?.str("future")?;
2305 Ok(())
2306 });
2307 let h = DataHeader::decode(&extended).unwrap();
2308 assert_eq!(h.content_len, Some(5));
2309 }
2310
2311 #[test]
2312 fn skipping_tolerates_nesting_up_to_the_depth_limit() {
2313 for depth in [1usize, limits::MAX_SKIP_DEPTH] {
2314 let bytes = encode_with(|e| {
2315 e.map(2)?;
2316 e.u64(data_key::CONTENT_LEN)?.u64(1)?;
2317 e.u64(50)?;
2318 for _ in 0..depth {
2319 e.array(1)?;
2320 }
2321 e.u64(1)?;
2322 Ok(())
2323 });
2324 let h = DataHeader::decode(&bytes).unwrap_or_else(|e| panic!("depth {depth}: {e}"));
2325 assert_eq!(h.content_len, Some(1), "depth {depth}");
2326 }
2327 }
2328
2329 #[test]
2330 fn skipping_rejects_nesting_beyond_the_depth_limit() {
2331 let bytes = encode_with(|e| {
2332 e.map(1)?;
2333 e.u64(50)?;
2334 for _ in 0..(limits::MAX_SKIP_DEPTH + 1) {
2335 e.array(1)?;
2336 }
2337 e.u64(1)?;
2338 Ok(())
2339 });
2340 assert_eq!(
2341 DataHeader::decode(&bytes).unwrap_err(),
2342 HeaderError::DepthExceeded
2343 );
2344 }
2345
2346 #[test]
2347 fn skipping_a_wide_shallow_structure_is_fine() {
2348 let bytes = encode_with(|e| {
2349 e.map(2)?;
2350 e.u64(data_key::CONTENT_LEN)?.u64(1)?;
2351 e.u64(40)?.array(64)?;
2352 for i in 0..64u64 {
2353 e.u64(i)?;
2354 }
2355 Ok(())
2356 });
2357 assert_eq!(DataHeader::decode(&bytes).unwrap().content_len, Some(1));
2358 }
2359
2360 #[test]
2363 fn duplicate_keys_are_rejected() {
2364 let bytes = encode_with(|e| {
2365 e.map(2)?;
2366 e.u64(1)?.u64(1)?;
2367 e.u64(1)?.u64(2)?;
2368 Ok(())
2369 });
2370 assert_eq!(
2371 DataHeader::decode(&bytes).unwrap_err(),
2372 HeaderError::DuplicateKey(1)
2373 );
2374 }
2375
2376 #[test]
2377 fn non_uint_keys_are_rejected() {
2378 let bytes = encode_with(|e| {
2379 e.map(1)?;
2380 e.str("endpoint")?.str("/t")?;
2381 Ok(())
2382 });
2383 assert_eq!(
2384 DataHeader::decode(&bytes).unwrap_err(),
2385 HeaderError::NonUintKey
2386 );
2387
2388 let negative = encode_with(|e| {
2389 e.map(1)?;
2390 e.i64(-1)?.u64(1)?;
2391 Ok(())
2392 });
2393 assert_eq!(
2394 DataHeader::decode(&negative).unwrap_err(),
2395 HeaderError::NonUintKey
2396 );
2397 }
2398
2399 #[test]
2400 fn indefinite_maps_are_rejected() {
2401 let bytes = encode_with(|e| {
2402 e.begin_map()?;
2403 e.u64(1)?.u64(1)?;
2404 e.end()?;
2405 Ok(())
2406 });
2407 assert_eq!(
2408 DataHeader::decode(&bytes).unwrap_err(),
2409 HeaderError::Indefinite
2410 );
2411 }
2412
2413 #[test]
2414 fn indefinite_arrays_are_rejected() {
2415 let bytes = encode_with(|e| {
2416 e.map(5)?;
2417 e.u64(0)?.begin_array()?.u64(0)?.end()?;
2418 e.u64(1)?.u64(1)?;
2419 e.u64(2)?.u64(1)?;
2420 e.u64(3)?.array(0)?;
2421 e.u64(4)?.array(0)?;
2422 Ok(())
2423 });
2424 assert_eq!(Hello::decode(&bytes).unwrap_err(), HeaderError::Indefinite);
2425 }
2426
2427 #[test]
2428 fn value_type_mismatches_are_rejected() {
2429 let bytes = encode_with(|e| {
2430 e.map(1)?;
2431 e.u64(data_key::CONTENT_LEN)?.str("not a number")?;
2432 Ok(())
2433 });
2434 assert!(matches!(
2435 DataHeader::decode(&bytes).unwrap_err(),
2436 HeaderError::Malformed(_)
2437 ));
2438 }
2439
2440 #[test]
2441 fn missing_required_keys_are_rejected() {
2442 let bytes = encode_with(|e| {
2444 e.map(1)?;
2445 e.u64(error_key::MESSAGE)?.str("why")?;
2446 Ok(())
2447 });
2448 assert_eq!(
2449 ErrorHeader::decode(&bytes).unwrap_err(),
2450 HeaderError::MissingKey(error_key::CODE)
2451 );
2452
2453 let bytes = encode_with(|e| {
2455 e.map(4)?;
2456 e.u64(0)?.array(1)?.u64(0)?;
2457 e.u64(1)?.u64(16384)?;
2458 e.u64(2)?.u64(16)?;
2459 e.u64(4)?.array(0)?;
2460 Ok(())
2461 });
2462 assert_eq!(
2463 Hello::decode(&bytes).unwrap_err(),
2464 HeaderError::MissingKey(hello_key::CAPABILITIES)
2465 );
2466 }
2467
2468 #[test]
2471 fn an_empty_filter_is_legal_and_survives_the_roundtrip() {
2472 let h = SubscriptionHeader::new("/md", "");
2473 let bytes = h.encode();
2474 assert_eq!(SubscriptionHeader::decode(&bytes).unwrap(), h);
2475 assert!(
2478 bytes.contains(&0x60),
2479 "the empty filter is encoded: {bytes:?}"
2480 );
2481 }
2482
2483 #[test]
2484 fn the_filter_grammar_accepts_what_docs_protocol_6_4_permits() {
2485 for ok in [
2486 "",
2487 "#",
2488 "px",
2489 "px.eur",
2490 "px.*",
2491 "*.eur",
2492 "sensors.*.temp",
2493 "px.#",
2494 "px.",
2495 "a..b",
2496 ] {
2497 assert_eq!(filter::validate(ok), Ok(()), "{ok:?} must be legal");
2498 }
2499 }
2500
2501 #[test]
2502 fn the_filter_grammar_rejects_partial_and_misplaced_wildcards() {
2503 for bad in [
2504 "px*", "*px", "p*x.eur", "px.e*ur", "#.px", "px.#.eur", "px#",
2505 ] {
2506 assert!(
2507 matches!(filter::validate(bad), Err(HeaderError::InvalidFilter(_))),
2508 "{bad:?} must be rejected"
2509 );
2510 }
2511 }
2512
2513 #[test]
2514 fn an_illegal_filter_is_rejected_at_the_codec_boundary() {
2515 let bytes = SubscriptionHeader::new("/md", "px.#.eur").encode();
2519 assert!(matches!(
2520 SubscriptionHeader::decode(&bytes),
2521 Err(HeaderError::InvalidFilter(_))
2522 ));
2523 let e: Error = HeaderError::InvalidFilter("`#` must be the final segment").into();
2524 assert!(e.to_string().contains("invalid topic filter"));
2525 }
2526
2527 #[test]
2528 fn subscription_strings_are_capped() {
2529 for (key, max) in [
2530 (subscription_key::ENDPOINT, limits::MAX_ENDPOINT_BYTES),
2531 (subscription_key::FILTER, limits::MAX_FILTER_BYTES),
2532 ] {
2533 let build = |len: usize| {
2534 let text = "a".repeat(len);
2535 let mut h = SubscriptionHeader::new("/md", "px.");
2536 if key == subscription_key::ENDPOINT {
2537 h.endpoint = text;
2538 } else {
2539 h.filter = text;
2540 }
2541 h.encode()
2542 };
2543 assert_eq!(
2544 SubscriptionHeader::decode(&build(max + 1)).unwrap_err(),
2545 HeaderError::StringTooLong {
2546 key,
2547 len: max + 1,
2548 max
2549 },
2550 "key {key}"
2551 );
2552 assert!(
2553 SubscriptionHeader::decode(&build(max)).is_ok(),
2554 "key {key} at cap"
2555 );
2556 }
2557 }
2558
2559 #[test]
2560 fn subscription_headers_require_both_keys() {
2561 let only = |key: u64| {
2562 encode_with(|e| {
2563 e.map(1)?;
2564 e.u64(key)?.str("/md")?;
2565 Ok(())
2566 })
2567 };
2568 assert_eq!(
2569 SubscriptionHeader::decode(&only(subscription_key::ENDPOINT)).unwrap_err(),
2570 HeaderError::MissingKey(subscription_key::FILTER)
2571 );
2572 assert_eq!(
2573 SubscriptionHeader::decode(&only(subscription_key::FILTER)).unwrap_err(),
2574 HeaderError::MissingKey(subscription_key::ENDPOINT)
2575 );
2576 }
2577
2578 #[test]
2579 fn subscription_headers_reject_malformed_input() {
2580 assert!(SubscriptionHeader::decode(&[]).is_err());
2581 let mut bytes = SubscriptionHeader::new("/md", "px.").encode();
2583 bytes.push(0xff);
2584 assert_eq!(
2585 SubscriptionHeader::decode(&bytes).unwrap_err(),
2586 HeaderError::TrailingBytes
2587 );
2588 let extended = encode_with(|e| {
2590 e.map(3)?;
2591 e.u64(0)?.str("/md")?;
2592 e.u64(1)?.str("px.")?;
2593 e.u64(40)?.array(2)?.u64(1)?.u64(2)?;
2594 Ok(())
2595 });
2596 assert_eq!(
2597 SubscriptionHeader::decode(&extended).unwrap(),
2598 SubscriptionHeader::new("/md", "px.")
2599 );
2600 }
2601
2602 #[test]
2603 fn oversized_strings_are_rejected_per_field() {
2604 let with_text = |key: u64, text: String| -> Vec<u8> {
2606 let mut h = DataHeader::reply();
2607 match key {
2608 data_key::ENDPOINT => h.endpoint = Some(text),
2609 data_key::CONTENT_TYPE => h.content_type = Some(text),
2610 data_key::TRACEPARENT => h.traceparent = Some(text),
2611 data_key::TRACESTATE => h.tracestate = Some(text),
2612 data_key::TOPIC => h.topic = Some(text),
2613 other => panic!("key {other} is not a text field"),
2614 }
2615 h.encode()
2616 };
2617 let cases: [(u64, usize); 5] = [
2618 (data_key::ENDPOINT, limits::MAX_ENDPOINT_BYTES),
2619 (data_key::CONTENT_TYPE, limits::MAX_CONTENT_TYPE_BYTES),
2620 (data_key::TRACEPARENT, limits::MAX_TRACEPARENT_BYTES),
2621 (data_key::TRACESTATE, limits::MAX_TRACESTATE_BYTES),
2622 (data_key::TOPIC, limits::MAX_TOPIC_BYTES),
2623 ];
2624 for (key, max) in cases {
2625 assert_eq!(
2626 DataHeader::decode(&with_text(key, "a".repeat(max + 1))).unwrap_err(),
2627 HeaderError::StringTooLong {
2628 key,
2629 len: max + 1,
2630 max
2631 },
2632 "key {key}"
2633 );
2634 assert!(
2635 DataHeader::decode(&with_text(key, "a".repeat(max))).is_ok(),
2636 "key {key} at cap"
2637 );
2638 }
2639 }
2640
2641 #[test]
2642 fn unordered_keys_are_rejected() {
2643 let bytes = encode_with(|e| {
2646 e.map(3)?;
2647 e.u64(2)?.str("t")?;
2648 e.u64(1)?.u64(1)?;
2649 e.u64(3)?.str("p")?;
2650 Ok(())
2651 });
2652 assert_eq!(
2653 DataHeader::decode(&bytes).unwrap_err(),
2654 HeaderError::UnorderedKey(1)
2655 );
2656 }
2657
2658 #[test]
2659 fn duplicate_extension_keys_are_rejected() {
2660 let bytes = encode_with(|e| {
2661 e.map(3)?;
2662 e.u64(1)?.u64(1)?;
2663 e.u64(1000)?.u64(1)?;
2664 e.u64(1000)?.u64(2)?;
2665 Ok(())
2666 });
2667 assert_eq!(
2668 DataHeader::decode(&bytes).unwrap_err(),
2669 HeaderError::DuplicateKey(1000)
2670 );
2671 }
2672
2673 #[test]
2674 fn oversized_error_messages_are_rejected() {
2675 let big = "m".repeat(limits::MAX_MESSAGE_BYTES + 1);
2676 let bytes = encode_with(|e| {
2677 e.map(2)?;
2678 e.u64(error_key::CODE)?.u64(2)?;
2679 e.u64(error_key::MESSAGE)?.str(&big)?;
2680 Ok(())
2681 });
2682 assert_eq!(
2683 ErrorHeader::decode(&bytes).unwrap_err(),
2684 HeaderError::StringTooLong {
2685 key: error_key::MESSAGE,
2686 len: limits::MAX_MESSAGE_BYTES + 1,
2687 max: limits::MAX_MESSAGE_BYTES
2688 }
2689 );
2690 }
2691
2692 #[test]
2693 fn oversized_lists_are_rejected_without_allocating() {
2694 let bytes = encode_with(|e| {
2696 e.map(1)?;
2697 e.u64(0)?.array(u64::from(u32::MAX))?;
2698 Ok(())
2699 });
2700 assert_eq!(
2701 Hello::decode(&bytes).unwrap_err(),
2702 HeaderError::ListTooLong {
2703 key: hello_key::VERSIONS,
2704 len: u64::from(u32::MAX),
2705 max: limits::MAX_LIST_ITEMS
2706 }
2707 );
2708 }
2709
2710 #[test]
2711 fn lists_exactly_at_the_cap_are_accepted() {
2712 let bytes = encode_with(|e| {
2713 e.map(5)?;
2714 e.u64(0)?.array(limits::MAX_LIST_ITEMS as u64)?;
2715 for i in 0..limits::MAX_LIST_ITEMS as u64 {
2716 e.u64(i)?;
2717 }
2718 e.u64(1)?.u64(16384)?;
2719 e.u64(2)?.u64(16)?;
2720 e.u64(3)?.array(0)?;
2721 e.u64(4)?.array(0)?;
2722 Ok(())
2723 });
2724 assert_eq!(
2725 Hello::decode(&bytes).unwrap().versions.len(),
2726 limits::MAX_LIST_ITEMS
2727 );
2728 }
2729
2730 #[test]
2731 fn trailing_bytes_are_rejected() {
2732 let mut bytes = ErrorHeader::new(ErrorCode::Rejected).encode();
2733 bytes.push(0xff);
2734 assert_eq!(
2735 ErrorHeader::decode(&bytes).unwrap_err(),
2736 HeaderError::TrailingBytes
2737 );
2738 }
2739
2740 #[test]
2741 fn truncated_headers_are_rejected() {
2742 let full = DataHeader::addressed("/t").encode();
2743 for cut in 0..full.len() {
2744 assert!(
2745 DataHeader::decode(&full[..cut]).is_err(),
2746 "prefix of {cut} bytes must not decode"
2747 );
2748 }
2749 }
2750
2751 #[test]
2752 fn empty_input_is_rejected_for_every_header() {
2753 assert!(Hello::decode(&[]).is_err());
2754 assert!(DataHeader::decode(&[]).is_err());
2755 assert!(ErrorHeader::decode(&[]).is_err());
2756 assert!(SubscriptionHeader::decode(&[]).is_err());
2757 }
2758
2759 #[test]
2760 fn tags_are_rejected() {
2761 let bytes = encode_with(|e| {
2764 e.map(1)?;
2765 e.u64(50)?.tag(minicbor::data::IanaTag::Cbor)?.u64(1)?;
2766 Ok(())
2767 });
2768 assert_eq!(
2769 DataHeader::decode(&bytes).unwrap_err(),
2770 HeaderError::Malformed("tags are not allowed")
2771 );
2772 }
2773
2774 #[test]
2777 fn unknown_error_codes_survive_decoding() {
2778 let err = ErrorHeader {
2779 code: 99,
2780 message: None,
2781 };
2782 let decoded = ErrorHeader::decode(&err.encode()).unwrap();
2783 assert_eq!(decoded.code, 99);
2784 assert_eq!(decoded.error_code(), None);
2785 }
2786
2787 #[test]
2788 fn header_errors_become_protocol_errors() {
2789 let e: Error = HeaderError::DuplicateKey(3).into();
2790 assert!(matches!(e, Error::Protocol(_)));
2791 assert!(e.to_string().contains("duplicate header key 3"));
2792 }
2793}