use crate::{CborDeserialize, CborDeserializer, CborMajorType, Error};
use alloc::string::String;
use core::fmt;
pub type DetailedResult<T> = core::result::Result<T, DetailedError>;
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct DetailedError {
pub error: Error,
pub context: ErrorContext,
}
impl DetailedError {
pub fn new(error: Error, context: ErrorContext) -> Self {
Self { error, context }
}
pub fn into_error(self) -> Error {
self.error
}
}
impl From<Error> for DetailedError {
fn from(error: Error) -> Self {
Self {
error,
context: ErrorContext::None,
}
}
}
impl fmt::Display for DetailedError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self.context {
ErrorContext::None => write!(f, "{}", self.error),
context => write!(f, "{} ({context:?})", self.error),
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for DetailedError {}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum ErrorContext {
None,
Cbor(CborErrorKind),
Cose(CoseErrorKind),
MissingField(String),
Field(String),
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum CborErrorKind {
TrailingData {
position: usize,
len: usize,
},
UnexpectedType {
expected: Option<CborMajorType>,
actual: Option<CborMajorType>,
},
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum CoseErrorKind {
MalformedEnvelope,
MissingDetachedPayload,
KeyMismatch,
}
pub fn from_slice_detailed<'de, T: CborDeserialize<'de>>(input: &'de [u8]) -> DetailedResult<T> {
let mut deserializer = CborDeserializer::new(input);
let value = T::deserialize(&mut deserializer).map_err(|error| {
let actual = deserializer.decoder_mut().peek_type();
DetailedError::new(
error,
ErrorContext::Cbor(CborErrorKind::UnexpectedType {
expected: None,
actual,
}),
)
})?;
if deserializer.is_finished() {
Ok(value)
} else {
Err(DetailedError::new(
Error::CborMalformed,
ErrorContext::Cbor(CborErrorKind::TrailingData {
position: deserializer.position(),
len: input.len(),
}),
))
}
}