1use super::*;
2
3use half::f16;
4
5/// A semantic representation of a CBOR item header
6///
7/// This structure represents the valid values of a CBOR item header and is
8/// used extensively when serializing or deserializing CBOR items. Note well
9/// that this structure **DOES NOT** represent the body (i.e. suffix) of the
10/// CBOR item. You must parse the body yourself based on the contents of the
11/// `Header`. However, utility functions are provided for this (see:
12/// `Decoder::bytes()` and `Decoder::text()`).
13#[derive(Copy, Clone, Debug, PartialEq)]
14pub enum Header {
15 /// A positive integer
16 Positive(u64),
17
18 /// A negative integer
19 ///
20 /// Note well that this value has all bits inverted from a normal signed
21 /// integer. For example, to convert the `u64` to a `i128` you would do
22 /// this: `neg as i128 ^ !0`.
23 Negative(u64),
24
25 /// A floating point value
26 Float(f64),
27
28 /// A "simple" value
29 Simple(u8),
30
31 /// A tag
32 Tag(u64),
33
34 /// The "break" value
35 ///
36 /// This value is used to terminate indefinite length arrays and maps,
37 /// as well as segmented byte or text items.
38 Break,
39
40 /// A bytes item
41 ///
42 /// The value contained in this variant indicates the length of the bytes
43 /// which follow or, if `None`, segmented bytes input.
44 ///
45 /// A best practice is to call `Decoder::bytes()` immediately after
46 /// first pulling a bytes item header since this utility function
47 /// encapsulates all the logic needed to handle segmentation.
48 Bytes(Option<usize>),
49
50 /// A text item
51 ///
52 /// The value contained in this variant indicates the length of the text
53 /// which follows (in bytes) or, if `None`, segmented text input.
54 ///
55 /// A best practice is to call `Decoder::text()` immediately after
56 /// first pulling a text item header since this utility function
57 /// encapsulates all the logic needed to handle segmentation.
58 Text(Option<usize>),
59
60 /// An array item
61 ///
62 /// The value contained in this variant indicates the length of the array
63 /// which follows (in items) or, if `None`, an indefinite length array
64 /// terminated by a "break" value.
65 Array(Option<usize>),
66
67 /// An map item
68 ///
69 /// The value contained in this variant indicates the length of the map
70 /// which follows (in item pairs) or, if `None`, an indefinite length map
71 /// terminated by a "break" value.
72 Map(Option<usize>),
73}
74
75impl TryFrom<Title> for Header {
76 type Error = InvalidError;
77
78 fn try_from(title: Title) -> Result<Self, Self::Error> {
79 let opt = |minor| {
80 Some(match minor {
81 Minor::This(x) => x.into(),
82 Minor::Next1(x) => u8::from_be_bytes(x).into(),
83 Minor::Next2(x) => u16::from_be_bytes(x).into(),
84 Minor::Next4(x) => u32::from_be_bytes(x).into(),
85 Minor::Next8(x) => u64::from_be_bytes(x),
86 Minor::More => return None,
87 })
88 };
89
90 let int = |m| opt(m).ok_or(InvalidError(()));
91
92 let len = |m| {
93 opt(m)
94 .map(usize::try_from)
95 .transpose()
96 .or(Err(InvalidError(())))
97 };
98
99 Ok(match title {
100 Title(Major::Positive, minor) => Self::Positive(int(minor)?),
101 Title(Major::Negative, minor) => Self::Negative(int(minor)?),
102 Title(Major::Bytes, minor) => Self::Bytes(len(minor)?),
103 Title(Major::Text, minor) => Self::Text(len(minor)?),
104 Title(Major::Array, minor) => Self::Array(len(minor)?),
105 Title(Major::Map, minor) => Self::Map(len(minor)?),
106 Title(Major::Tag, minor) => Self::Tag(int(minor)?),
107
108 Title(Major::Other, Minor::More) => Self::Break,
109 Title(Major::Other, Minor::This(x)) => Self::Simple(x),
110 Title(Major::Other, Minor::Next1(x)) => Self::Simple(x[0]),
111 Title(Major::Other, Minor::Next2(x)) => Self::Float(f16::from_be_bytes(x).into()),
112 Title(Major::Other, Minor::Next4(x)) => Self::Float(f32::from_be_bytes(x).into()),
113 Title(Major::Other, Minor::Next8(x)) => Self::Float(f64::from_be_bytes(x)),
114 })
115 }
116}
117
118impl From<Header> for Title {
119 fn from(header: Header) -> Self {
120 let int = |i: u64| match i {
121 x if x <= 23 => Minor::This(i as u8),
122 x if x <= core::u8::MAX as u64 => Minor::Next1([i as u8]),
123 x if x <= core::u16::MAX as u64 => Minor::Next2((i as u16).to_be_bytes()),
124 x if x <= core::u32::MAX as u64 => Minor::Next4((i as u32).to_be_bytes()),
125 x => Minor::Next8(x.to_be_bytes()),
126 };
127
128 let len = |l: Option<usize>| l.map(|x| int(x as u64)).unwrap_or(Minor::More);
129
130 match header {
131 Header::Positive(x) => Title(Major::Positive, int(x)),
132 Header::Negative(x) => Title(Major::Negative, int(x)),
133 Header::Bytes(x) => Title(Major::Bytes, len(x)),
134 Header::Text(x) => Title(Major::Text, len(x)),
135 Header::Array(x) => Title(Major::Array, len(x)),
136 Header::Map(x) => Title(Major::Map, len(x)),
137 Header::Tag(x) => Title(Major::Tag, int(x)),
138
139 Header::Break => Title(Major::Other, Minor::More),
140
141 Header::Simple(x) => match x {
142 x @ 0..=23 => Title(Major::Other, Minor::This(x)),
143 x => Title(Major::Other, Minor::Next1([x])),
144 },
145
146 Header::Float(n64) => {
147 let n16 = f16::from_f64(n64);
148 let n32 = n64 as f32;
149
150 Title(
151 Major::Other,
152 if f64::from(n16).to_bits() == n64.to_bits() {
153 Minor::Next2(n16.to_be_bytes())
154 } else if f64::from(n32).to_bits() == n64.to_bits() {
155 Minor::Next4(n32.to_be_bytes())
156 } else {
157 Minor::Next8(n64.to_be_bytes())
158 },
159 )
160 }
161 }
162 }
163}
164