/rust/registry/src/index.crates.io-6f17d22bba15001f/ciborium-ll-0.2.2/src/hdr.rs
Line | Count | Source (jump to first uncovered line) |
1 | | use super::*; |
2 | | |
3 | | use 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)] |
14 | | pub 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 | | |
75 | | impl TryFrom<Title> for Header { |
76 | | type Error = InvalidError; |
77 | | |
78 | 0 | fn try_from(title: Title) -> Result<Self, Self::Error> { |
79 | 0 | let opt = |minor| { |
80 | 0 | Some(match minor { |
81 | 0 | Minor::This(x) => x.into(), |
82 | 0 | Minor::Next1(x) => u8::from_be_bytes(x).into(), |
83 | 0 | Minor::Next2(x) => u16::from_be_bytes(x).into(), |
84 | 0 | Minor::Next4(x) => u32::from_be_bytes(x).into(), |
85 | 0 | Minor::Next8(x) => u64::from_be_bytes(x), |
86 | 0 | Minor::More => return None, |
87 | | }) |
88 | 0 | }; |
89 | | |
90 | 0 | let int = |m| opt(m).ok_or(InvalidError(())); |
91 | | |
92 | 0 | let len = |m| { |
93 | 0 | opt(m) |
94 | 0 | .map(usize::try_from) |
95 | 0 | .transpose() |
96 | 0 | .or(Err(InvalidError(()))) |
97 | 0 | }; |
98 | | |
99 | 0 | Ok(match title { |
100 | 0 | Title(Major::Positive, minor) => Self::Positive(int(minor)?), |
101 | 0 | Title(Major::Negative, minor) => Self::Negative(int(minor)?), |
102 | 0 | Title(Major::Bytes, minor) => Self::Bytes(len(minor)?), |
103 | 0 | Title(Major::Text, minor) => Self::Text(len(minor)?), |
104 | 0 | Title(Major::Array, minor) => Self::Array(len(minor)?), |
105 | 0 | Title(Major::Map, minor) => Self::Map(len(minor)?), |
106 | 0 | Title(Major::Tag, minor) => Self::Tag(int(minor)?), |
107 | | |
108 | 0 | Title(Major::Other, Minor::More) => Self::Break, |
109 | 0 | Title(Major::Other, Minor::This(x)) => Self::Simple(x), |
110 | 0 | Title(Major::Other, Minor::Next1(x)) => Self::Simple(x[0]), |
111 | 0 | Title(Major::Other, Minor::Next2(x)) => Self::Float(f16::from_be_bytes(x).into()), |
112 | 0 | Title(Major::Other, Minor::Next4(x)) => Self::Float(f32::from_be_bytes(x).into()), |
113 | 0 | Title(Major::Other, Minor::Next8(x)) => Self::Float(f64::from_be_bytes(x)), |
114 | | }) |
115 | 0 | } |
116 | | } |
117 | | |
118 | | impl From<Header> for Title { |
119 | 0 | fn from(header: Header) -> Self { |
120 | 0 | let int = |i: u64| match i { |
121 | 0 | x if x <= 23 => Minor::This(i as u8), |
122 | 0 | x if x <= core::u8::MAX as u64 => Minor::Next1([i as u8]), |
123 | 0 | x if x <= core::u16::MAX as u64 => Minor::Next2((i as u16).to_be_bytes()), |
124 | 0 | x if x <= core::u32::MAX as u64 => Minor::Next4((i as u32).to_be_bytes()), |
125 | 0 | x => Minor::Next8(x.to_be_bytes()), |
126 | 0 | }; |
127 | | |
128 | 0 | let len = |l: Option<usize>| l.map(|x| int(x as u64)).unwrap_or(Minor::More); |
129 | | |
130 | 0 | match header { |
131 | 0 | Header::Positive(x) => Title(Major::Positive, int(x)), |
132 | 0 | Header::Negative(x) => Title(Major::Negative, int(x)), |
133 | 0 | Header::Bytes(x) => Title(Major::Bytes, len(x)), |
134 | 0 | Header::Text(x) => Title(Major::Text, len(x)), |
135 | 0 | Header::Array(x) => Title(Major::Array, len(x)), |
136 | 0 | Header::Map(x) => Title(Major::Map, len(x)), |
137 | 0 | Header::Tag(x) => Title(Major::Tag, int(x)), |
138 | | |
139 | 0 | Header::Break => Title(Major::Other, Minor::More), |
140 | | |
141 | 0 | Header::Simple(x) => match x { |
142 | 0 | x @ 0..=23 => Title(Major::Other, Minor::This(x)), |
143 | 0 | x => Title(Major::Other, Minor::Next1([x])), |
144 | | }, |
145 | | |
146 | 0 | Header::Float(n64) => { |
147 | 0 | let n16 = f16::from_f64(n64); |
148 | 0 | let n32 = n64 as f32; |
149 | 0 |
|
150 | 0 | Title( |
151 | 0 | Major::Other, |
152 | 0 | if f64::from(n16).to_bits() == n64.to_bits() { |
153 | 0 | Minor::Next2(n16.to_be_bytes()) |
154 | 0 | } else if f64::from(n32).to_bits() == n64.to_bits() { |
155 | 0 | Minor::Next4(n32.to_be_bytes()) |
156 | | } else { |
157 | 0 | Minor::Next8(n64.to_be_bytes()) |
158 | | }, |
159 | | ) |
160 | | } |
161 | | } |
162 | 0 | } |
163 | | } |