Coverage Report

Created: 2025-02-25 06:39

/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
}