summaryrefslogtreecommitdiffstats
path: root/vendor/ciborium-ll/src/hdr.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/ciborium-ll/src/hdr.rs')
-rw-r--r--vendor/ciborium-ll/src/hdr.rs163
1 files changed, 163 insertions, 0 deletions
diff --git a/vendor/ciborium-ll/src/hdr.rs b/vendor/ciborium-ll/src/hdr.rs
new file mode 100644
index 000000000..dec178815
--- /dev/null
+++ b/vendor/ciborium-ll/src/hdr.rs
@@ -0,0 +1,163 @@
+use super::*;
+
+use half::f16;
+
+/// A semantic representation of a CBOR item header
+///
+/// This structure represents the valid values of a CBOR item header and is
+/// used extensively when serializing or deserializing CBOR items. Note well
+/// that this structure **DOES NOT** represent the body (i.e. suffix) of the
+/// CBOR item. You must parse the body yourself based on the contents of the
+/// `Header`. However, utility functions are provided for this (see:
+/// `Decoder::bytes()` and `Decoder::text()`).
+#[derive(Copy, Clone, Debug, PartialEq)]
+pub enum Header {
+ /// A positive integer
+ Positive(u64),
+
+ /// A negative integer
+ ///
+ /// Note well that this value has all bits inverted from a normal signed
+ /// integer. For example, to convert the `u64` to a `i128` you would do
+ /// this: `neg as i128 ^ !0`.
+ Negative(u64),
+
+ /// A floating point value
+ Float(f64),
+
+ /// A "simple" value
+ Simple(u8),
+
+ /// A tag
+ Tag(u64),
+
+ /// The "break" value
+ ///
+ /// This value is used to terminate indefinite length arrays and maps,
+ /// as well as segmented byte or text items.
+ Break,
+
+ /// A bytes item
+ ///
+ /// The value contained in this variant indicates the length of the bytes
+ /// which follow or, if `None`, segmented bytes input.
+ ///
+ /// A best practice is to call `Decoder::bytes()` immediately after
+ /// first pulling a bytes item header since this utility function
+ /// encapsulates all the logic needed to handle segmentation.
+ Bytes(Option<usize>),
+
+ /// A text item
+ ///
+ /// The value contained in this variant indicates the length of the text
+ /// which follows (in bytes) or, if `None`, segmented text input.
+ ///
+ /// A best practice is to call `Decoder::text()` immediately after
+ /// first pulling a text item header since this utility function
+ /// encapsulates all the logic needed to handle segmentation.
+ Text(Option<usize>),
+
+ /// An array item
+ ///
+ /// The value contained in this variant indicates the length of the array
+ /// which follows (in items) or, if `None`, an indefinite length array
+ /// terminated by a "break" value.
+ Array(Option<usize>),
+
+ /// An map item
+ ///
+ /// The value contained in this variant indicates the length of the map
+ /// which follows (in item pairs) or, if `None`, an indefinite length map
+ /// terminated by a "break" value.
+ Map(Option<usize>),
+}
+
+impl TryFrom<Title> for Header {
+ type Error = InvalidError;
+
+ fn try_from(title: Title) -> Result<Self, Self::Error> {
+ let opt = |minor| {
+ Some(match minor {
+ Minor::This(x) => x.into(),
+ Minor::Next1(x) => u8::from_be_bytes(x).into(),
+ Minor::Next2(x) => u16::from_be_bytes(x).into(),
+ Minor::Next4(x) => u32::from_be_bytes(x).into(),
+ Minor::Next8(x) => u64::from_be_bytes(x),
+ Minor::More => return None,
+ })
+ };
+
+ let int = |m| opt(m).ok_or(InvalidError(()));
+
+ let len = |m| {
+ opt(m)
+ .map(usize::try_from)
+ .transpose()
+ .or(Err(InvalidError(())))
+ };
+
+ Ok(match title {
+ Title(Major::Positive, minor) => Self::Positive(int(minor)?),
+ Title(Major::Negative, minor) => Self::Negative(int(minor)?),
+ Title(Major::Bytes, minor) => Self::Bytes(len(minor)?),
+ Title(Major::Text, minor) => Self::Text(len(minor)?),
+ Title(Major::Array, minor) => Self::Array(len(minor)?),
+ Title(Major::Map, minor) => Self::Map(len(minor)?),
+ Title(Major::Tag, minor) => Self::Tag(int(minor)?),
+
+ Title(Major::Other, Minor::More) => Self::Break,
+ Title(Major::Other, Minor::This(x)) => Self::Simple(x),
+ Title(Major::Other, Minor::Next1(x)) => Self::Simple(x[0]),
+ Title(Major::Other, Minor::Next2(x)) => Self::Float(f16::from_be_bytes(x).into()),
+ Title(Major::Other, Minor::Next4(x)) => Self::Float(f32::from_be_bytes(x).into()),
+ Title(Major::Other, Minor::Next8(x)) => Self::Float(f64::from_be_bytes(x)),
+ })
+ }
+}
+
+impl From<Header> for Title {
+ fn from(header: Header) -> Self {
+ let int = |i: u64| match i {
+ x if x <= 23 => Minor::This(i as u8),
+ x if x <= core::u8::MAX as u64 => Minor::Next1([i as u8]),
+ x if x <= core::u16::MAX as u64 => Minor::Next2((i as u16).to_be_bytes()),
+ x if x <= core::u32::MAX as u64 => Minor::Next4((i as u32).to_be_bytes()),
+ x => Minor::Next8(x.to_be_bytes()),
+ };
+
+ let len = |l: Option<usize>| l.map(|x| int(x as u64)).unwrap_or(Minor::More);
+
+ match header {
+ Header::Positive(x) => Title(Major::Positive, int(x)),
+ Header::Negative(x) => Title(Major::Negative, int(x)),
+ Header::Bytes(x) => Title(Major::Bytes, len(x)),
+ Header::Text(x) => Title(Major::Text, len(x)),
+ Header::Array(x) => Title(Major::Array, len(x)),
+ Header::Map(x) => Title(Major::Map, len(x)),
+ Header::Tag(x) => Title(Major::Tag, int(x)),
+
+ Header::Break => Title(Major::Other, Minor::More),
+
+ Header::Simple(x) => match x {
+ x @ 0..=23 => Title(Major::Other, Minor::This(x)),
+ x => Title(Major::Other, Minor::Next1([x])),
+ },
+
+ Header::Float(n64) => {
+ let n16 = f16::from_f64(n64);
+ let n32 = n64 as f32;
+
+ Title(
+ Major::Other,
+ if f64::from(n16).to_bits() == n64.to_bits() {
+ Minor::Next2(n16.to_be_bytes())
+ } else if f64::from(n32).to_bits() == n64.to_bits() {
+ Minor::Next4(n32.to_be_bytes())
+ } else {
+ Minor::Next8(n64.to_be_bytes())
+ },
+ )
+ }
+ }
+ }
+}