| 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 | 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 | |
| 118 | impl 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 | |