dcbor/
error.rs

1import_stdlib!();
2
3use core::str::Utf8Error;
4
5use crate::tag::Tag;
6
7/// A comprehensive set of errors that can occur during CBOR encoding and
8/// decoding operations, with special focus on enforcing the deterministic
9/// encoding rules specified in the dCBOR specification.
10///
11/// The dCBOR implementation validates all encoded CBOR against the
12/// deterministic encoding requirements of RFC 8949 §4.2.1, plus additional
13/// constraints defined in the dCBOR application profile. These errors represent
14/// all the possible validation failures and decoding issues that can arise.
15///
16/// # Examples
17///
18/// ```
19/// use dcbor::prelude::*;
20///
21/// // Handling the WrongType error when trying to convert a different type
22/// let cbor_string = CBOR::from("hello");
23/// let result = cbor_string.try_into_byte_string();
24///
25/// assert!(result.is_err());
26/// if let Err(e) = result {
27///     assert!(e.to_string().contains("not the expected type"));
28/// }
29/// ```
30#[derive(Debug, ThisError)]
31pub enum Error {
32    /// The CBOR data ended prematurely during decoding, before a complete CBOR
33    /// item could be decoded. This typically happens when a CBOR item's
34    /// structure indicates more data than is actually present.
35    #[error("early end of CBOR data")]
36    Underrun,
37
38    /// An unsupported or invalid value was encountered in a CBOR header byte.
39    /// The parameter contains the unsupported header byte value.
40    /// This can occur when decoding CBOR that uses unsupported features or is
41    /// malformed.
42    #[error("unsupported value in CBOR header")]
43    UnsupportedHeaderValue(u8),
44
45    /// A CBOR numeric value was encoded in a non-canonical form, violating the
46    /// deterministic encoding requirement of dCBOR (per Section 2.3 of the
47    /// dCBOR specification).
48    ///
49    /// This error is triggered when:
50    /// - An integer is not encoded in its shortest possible form
51    /// - A floating point value that could be represented as an integer was not
52    ///   reduced
53    /// - A NaN value was not encoded in its canonical form (`f97e00`)
54    #[error("a CBOR numeric value was encoded in non-canonical form")]
55    NonCanonicalNumeric,
56
57    /// An invalid CBOR simple value was encountered during decoding.
58    ///
59    /// Per Section 2.4 of the dCBOR specification, only `false`, `true`,
60    /// `null`, and floating point values are valid simple values in dCBOR.
61    /// All other major type 7 values are invalid.
62    #[error("an invalid CBOR simple value was encountered")]
63    InvalidSimpleValue,
64
65    /// A CBOR text string was not valid UTF-8. The parameter contains the
66    /// specific UTF-8 error.
67    ///
68    /// All CBOR text strings (major type 3) must be valid UTF-8 per RFC 8949.
69    #[error(
70        "an invalidly-encoded UTF-8 string was encountered in the CBOR ({0:?})"
71    )]
72    InvalidString(str::Utf8Error),
73
74    /// A CBOR text string was not encoded in Unicode Canonical Normalization
75    /// Form C (NFC).
76    ///
77    /// Per Section 2.5 of the dCBOR specification, all text strings must be in
78    /// NFC form, and decoders must reject any encoded text strings that are
79    /// not in NFC.
80    #[error(
81        "a CBOR string was not encoded in Unicode Canonical Normalization Form C"
82    )]
83    NonCanonicalString,
84
85    /// The decoded CBOR item didn't consume all input data.
86    /// The parameter contains the number of unused bytes.
87    ///
88    /// This error occurs when decoding functions expect exactly one CBOR item
89    /// but the input contains additional data after a valid CBOR item.
90    #[error("the decoded CBOR had {0} extra bytes at the end")]
91    UnusedData(usize),
92
93    /// The keys in a decoded CBOR map were not in canonical lexicographic order
94    /// of their encoding.
95    ///
96    /// Per the CDE specification and Section 2.1 of dCBOR, map keys must be in
97    /// ascending lexicographic order of their encoded representation for
98    /// deterministic encoding.
99    #[error("the decoded CBOR map has keys that are not in canonical order")]
100    MisorderedMapKey,
101
102    /// A decoded CBOR map contains duplicate keys, which is invalid.
103    ///
104    /// Per Section 2.2 of the dCBOR specification, CBOR maps must not contain
105    /// duplicate keys, and decoders must reject encoded maps with duplicate
106    /// keys.
107    #[error("the decoded CBOR map has a duplicate key")]
108    DuplicateMapKey,
109
110    /// A requested key was not found in a CBOR map during data extraction.
111    #[error("missing CBOR map key")]
112    MissingMapKey,
113
114    /// A CBOR numeric value could not be represented in the specified target
115    /// numeric type.
116    ///
117    /// This occurs when attempting to convert a CBOR number to a Rust numeric
118    /// type that is too small to represent the value without loss of
119    /// precision.
120    #[error(
121        "the CBOR numeric value could not be represented in the specified numeric type"
122    )]
123    OutOfRange,
124
125    /// The CBOR value is not of the expected type for a conversion or
126    /// operation.
127    ///
128    /// This occurs when attempting to convert a CBOR value to a type that
129    /// doesn't match the actual CBOR item's type (e.g., trying to convert a
130    /// string to an integer).
131    #[error("the decoded CBOR value was not the expected type")]
132    WrongType,
133
134    /// The CBOR tagged value had a different tag than expected.
135    /// The first parameter is the expected tag, and the second is the actual
136    /// tag found.
137    #[error("expected CBOR tag {0}, but got {1}")]
138    WrongTag(Tag, Tag),
139
140    /// Invalid UTF‑8 in a text string.
141    #[error("invalid UTF‑8 string: {0}")]
142    InvalidUtf8(#[from] Utf8Error),
143
144    /// Invalid ISO 8601 date format.
145    #[error("invalid ISO 8601 date string: {0}")]
146    InvalidDate(String),
147
148    /// Custom error message.
149    #[error("{0}")]
150    Custom(String),
151}
152
153impl Error {
154    pub fn msg(s: impl Into<String>) -> Self { Error::Custom(s.into()) }
155}
156
157impl From<&str> for Error {
158    /// Converts a string slice into a `CBORError::Custom` variant.
159    fn from(error: &str) -> Self { Error::msg(error) }
160}
161
162impl From<String> for Error {
163    /// Converts a `String` into a `CBORError::Custom` variant.
164    fn from(error: String) -> Self { Error::msg(error) }
165}
166
167pub type Result<T> = StdResult<T, Error>;