cbor_core/error.rs
1use std::{fmt, io, string::FromUtf8Error};
2
3use crate::DataType;
4
5/// Errors produced by this crate.
6///
7/// Errors fall into three categories:
8///
9/// **Decoding errors** are returned by [`Value::decode`](crate::Value::decode),
10/// [`Value::read_from`](crate::Value::read_from),
11/// and [`Value::read_hex_from`](crate::Value::read_hex_from) when the input is not valid deterministic
12/// CBOR: [`Malformed`](Self::Malformed), [`NonDeterministic`](Self::NonDeterministic),
13/// [`UnexpectedEof`](Self::UnexpectedEof), [`LengthTooLarge`](Self::LengthTooLarge),
14/// [`InvalidUtf8`](Self::InvalidUtf8), [`InvalidHex`](Self::InvalidHex), [`InvalidBase64`](Self::InvalidBase64).
15///
16/// **Accessor errors** are returned by the `to_*`, `as_*`, and `into_*`
17/// methods on [`Value`](crate::Value) when the value does not match the requested type:
18/// [`IncompatibleType`](Self::IncompatibleType), [`Overflow`](Self::Overflow),
19/// [`NegativeUnsigned`](Self::NegativeUnsigned), [`Precision`](Self::Precision),
20/// [`InvalidSimpleValue`](Self::InvalidSimpleValue).
21///
22/// **Validation errors** are returned during construction of typed helpers
23/// like [`DateTime`](crate::DateTime) and [`EpochTime`](crate::EpochTime):
24/// [`InvalidFormat`](Self::InvalidFormat), [`InvalidValue`](Self::InvalidValue).
25///
26/// `Error` is `Copy`, `Eq`, `Ord`, and `Hash`, so it can be matched,
27/// compared, and used as a map key without allocation. I/O errors are
28/// handled separately by [`IoError`], which wraps either an `Error` or
29/// a [`std::io::Error`]. This separation keeps `Error` small and
30/// `Copy`-able while still supporting streaming operations that can
31/// fail with I/O problems.
32#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
33#[non_exhaustive]
34pub enum Error {
35 // --- Decoding errors ---
36 //
37 /// Binary CBOR data is structurally broken.
38 Malformed,
39 /// CBOR encoding is valid but not deterministic (non-shortest form, unsorted map keys, etc.).
40 NonDeterministic,
41 /// Input ended before a complete data item was read.
42 UnexpectedEof,
43 /// Declared length exceeds addressable memory or reasonable size.
44 LengthTooLarge,
45 /// Text string contains invalid UTF-8.
46 InvalidUtf8,
47 /// Hex input contains invalid characters.
48 InvalidHex,
49 /// Base64 input contains invalid characters.
50 InvalidBase64,
51
52 // --- Accessor errors ---
53 //
54 /// Accessor called on a value of the wrong CBOR type.
55 IncompatibleType(DataType),
56 /// Integer does not fit in the target type.
57 Overflow,
58 /// Attempted to read a negative integer as an unsigned type.
59 NegativeUnsigned,
60 /// Float conversion would lose precision.
61 Precision,
62 /// Simple value number is in the reserved range 24-31.
63 InvalidSimpleValue,
64
65 // --- Validation errors ---
66 //
67 /// A text field had invalid syntax for its expected format.
68 InvalidFormat,
69 /// A value violates semantic constraints.
70 InvalidValue,
71}
72
73impl fmt::Display for Error {
74 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
75 match self {
76 Self::Malformed => write!(f, "malformed CBOR encoding"),
77 Self::NonDeterministic => write!(f, "non-deterministic CBOR encoding"),
78 Self::UnexpectedEof => write!(f, "unexpected end of input"),
79 Self::LengthTooLarge => write!(f, "length exceeds reasonable size"),
80 Self::InvalidUtf8 => write!(f, "invalid UTF-8 in text string"),
81 Self::InvalidHex => write!(f, "invalid hex character"),
82 Self::InvalidBase64 => write!(f, "invalid base64 character"),
83 Self::IncompatibleType(t) => write!(f, "incompatible CBOR type {name}", name = t.name()),
84 Self::Overflow => write!(f, "integer overflow"),
85 Self::NegativeUnsigned => write!(f, "negative value for unsigned type"),
86 Self::Precision => write!(f, "float precision loss"),
87 Self::InvalidSimpleValue => write!(f, "invalid CBOR simple value"),
88 Self::InvalidFormat => write!(f, "invalid syntax for expected format"),
89 Self::InvalidValue => write!(f, "invalid value"),
90 }
91 }
92}
93
94impl std::error::Error for Error {}
95
96/// Convenience alias used throughout this crate.
97pub type Result<T> = std::result::Result<T, Error>;
98
99impl From<FromUtf8Error> for Error {
100 fn from(_error: FromUtf8Error) -> Self {
101 Self::InvalidUtf8
102 }
103}
104
105impl<T> From<Error> for Result<T> {
106 fn from(error: Error) -> Self {
107 Err(error)
108 }
109}
110
111/// Error type for IO related operations.
112///
113/// For streaming CBOR operations that may fail with either
114/// an I/O error or a data-level [`Error`].
115#[derive(Debug)]
116pub enum IoError {
117 /// Underlying I/O error from the reader or writer.
118 Io(io::Error),
119 /// CBOR-level error (malformed data, non-deterministic encoding, etc.).
120 Data(Error),
121}
122
123impl From<io::Error> for IoError {
124 fn from(error: io::Error) -> Self {
125 match error.kind() {
126 io::ErrorKind::UnexpectedEof => Error::UnexpectedEof.into(),
127 _other => Self::Io(error),
128 }
129 }
130}
131
132impl<E: Into<Error>> From<E> for IoError {
133 fn from(error: E) -> Self {
134 Self::Data(error.into())
135 }
136}
137
138impl<T> From<Error> for IoResult<T> {
139 fn from(error: Error) -> Self {
140 Err(IoError::Data(error))
141 }
142}
143
144/// Convenience alias for streaming CBOR operations.
145pub type IoResult<T> = std::result::Result<T, IoError>;