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>;