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 try_from(title: Title) -> Result<Self, Self::Error>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 { from(header: Header) -> Self119 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