use core::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CborErrorKind {
Decode,
Validate,
Encode,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum CborErrorCode {
InvalidLimits,
UnexpectedEof,
LengthOverflow,
TrailingBytes,
AllocationFailed,
DepthLimitExceeded,
TotalItemsLimitExceeded,
ArrayLenLimitExceeded,
MapLenLimitExceeded,
BytesLenLimitExceeded,
TextLenLimitExceeded,
UnsupportedMajorType,
ReservedAdditionalInfo,
IndefiniteLengthForbidden,
NonCanonicalEncoding,
MapKeyMustBeText,
DuplicateMapKey,
NonCanonicalMapOrder,
ForbiddenOrMalformedTag,
BignumNotCanonical,
BignumMustBeOutsideSafeRange,
UnsupportedSimpleValue,
IntegerOutsideSafeRange,
Utf8Invalid,
NegativeZeroForbidden,
NonCanonicalNaN,
SerdeError,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct CborError {
pub kind: CborErrorKind,
pub code: CborErrorCode,
pub offset: usize,
}
impl CborError {
#[inline]
#[must_use]
pub const fn decode(code: CborErrorCode, offset: usize) -> Self {
Self {
kind: CborErrorKind::Decode,
code,
offset,
}
}
#[inline]
#[must_use]
pub const fn validate(code: CborErrorCode, offset: usize) -> Self {
Self {
kind: CborErrorKind::Validate,
code,
offset,
}
}
#[inline]
#[must_use]
pub const fn encode(code: CborErrorCode) -> Self {
Self {
kind: CborErrorKind::Encode,
code,
offset: 0,
}
}
#[inline]
#[must_use]
pub const fn is_validation(self) -> bool {
matches!(self.kind, CborErrorKind::Validate)
}
}
impl fmt::Display for CborError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let msg = match self.code {
CborErrorCode::InvalidLimits => "invalid CBOR limits",
CborErrorCode::UnexpectedEof => "unexpected end of input",
CborErrorCode::LengthOverflow => "length overflow",
CborErrorCode::TrailingBytes => "trailing bytes after single CBOR item",
CborErrorCode::AllocationFailed => "allocation failed",
CborErrorCode::DepthLimitExceeded => "nesting depth limit exceeded",
CborErrorCode::TotalItemsLimitExceeded => "total items limit exceeded",
CborErrorCode::ArrayLenLimitExceeded => "array length exceeds decode limits",
CborErrorCode::MapLenLimitExceeded => "map length exceeds decode limits",
CborErrorCode::BytesLenLimitExceeded => "byte string length exceeds decode limits",
CborErrorCode::TextLenLimitExceeded => "text string length exceeds decode limits",
CborErrorCode::UnsupportedMajorType => "unsupported CBOR major type",
CborErrorCode::ReservedAdditionalInfo => "reserved additional info value",
CborErrorCode::IndefiniteLengthForbidden => "indefinite length forbidden",
CborErrorCode::NonCanonicalEncoding => "non-canonical integer/length encoding",
CborErrorCode::MapKeyMustBeText => "map keys must be text strings",
CborErrorCode::DuplicateMapKey => "duplicate map key",
CborErrorCode::NonCanonicalMapOrder => "non-canonical map key order",
CborErrorCode::ForbiddenOrMalformedTag => "forbidden or malformed CBOR tag",
CborErrorCode::BignumNotCanonical => {
"bignum magnitude must be canonical (non-empty, no leading zero)"
}
CborErrorCode::BignumMustBeOutsideSafeRange => "bignum must be outside int_safe range",
CborErrorCode::UnsupportedSimpleValue => "unsupported CBOR simple value",
CborErrorCode::IntegerOutsideSafeRange => "integer outside int_safe range",
CborErrorCode::Utf8Invalid => "text must be valid UTF-8",
CborErrorCode::NegativeZeroForbidden => "negative zero forbidden",
CborErrorCode::NonCanonicalNaN => "non-canonical NaN encoding",
CborErrorCode::SerdeError => "serde conversion failed",
};
match self.kind {
CborErrorKind::Encode => write!(f, "cbor encode failed: {msg}"),
CborErrorKind::Decode => write!(f, "cbor decode failed at {}: {msg}", self.offset),
CborErrorKind::Validate => {
write!(f, "cbor validation failed at {}: {msg}", self.offset)
}
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for CborError {}