cbor_data/
error.rs

1use std::{
2    fmt::{Debug, Display},
3    str::Utf8Error,
4};
5
6/// What the parser was looking for when bytes ran out
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub enum WhileParsing {
9    ItemHeader,
10    HeaderValue,
11    ArrayItem,
12    DictItem,
13    BytesFragment,
14    BytesValue,
15    StringFragment,
16    StringValue,
17}
18
19/// Errors that may be encountered when parsing CBOR bytes
20#[derive(Debug, Clone, PartialEq, Eq)]
21#[non_exhaustive]
22pub enum ErrorKind {
23    /// lower five bits of item header were > 27
24    InvalidInfo,
25    /// extra bytes were left while extracting the top-level item or decoding a TAG_CBOR_ITEM byte string
26    TrailingGarbage,
27    /// indefinite size encoding of (byte or text) strings requires definite size chunks to have the same major type
28    InvalidStringFragment,
29    /// a text string (or fragment thereof) contained invalid UTF-8 data
30    InvalidUtf8(Utf8Error),
31    /// the provided bytes are incomplete
32    ///
33    /// This error can be flagged also at the end of a TAG_CBOR_ITEM byte string, i.e.
34    /// in the middle of the validated bytes.
35    UnexpectedEof(WhileParsing),
36}
37
38impl Display for ErrorKind {
39    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
40        match self {
41            ErrorKind::InvalidInfo => write!(f, "invalid item header"),
42            ErrorKind::TrailingGarbage => write!(f, "trailing garbage"),
43            ErrorKind::InvalidStringFragment => write!(f, "string fragment of wrong major type"),
44            ErrorKind::InvalidUtf8(e) => write!(f, "UTF-8 error `{}`", e),
45            ErrorKind::UnexpectedEof(w) => write!(f, "ran out of bytes while parsing {:?}", w),
46        }
47    }
48}
49
50/// Error container for parsing problems
51#[derive(Clone, PartialEq, Eq)]
52pub struct ParseError {
53    offset: usize,
54    kind: ErrorKind,
55}
56
57impl ParseError {
58    /// Get a reference to the parse error's offset.
59    pub fn offset(&self) -> usize {
60        self.offset
61    }
62
63    /// Get a reference to the parse error's kind.
64    pub fn kind(&self) -> ErrorKind {
65        self.kind.clone()
66    }
67}
68
69impl Display for ParseError {
70    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
71        write!(f, "{} at offset {}", self.kind, self.offset)
72    }
73}
74
75impl std::error::Error for ParseError {}
76
77impl Debug for ParseError {
78    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
79        Display::fmt(self, f)
80    }
81}
82
83pub(crate) struct InternalError<'a> {
84    position: &'a [u8],
85    kind: ErrorKind,
86}
87
88impl<'a> InternalError<'a> {
89    pub fn new(position: &'a [u8], kind: ErrorKind) -> Self {
90        Self { position, kind }
91    }
92
93    pub fn offset(&self, base: &[u8]) -> usize {
94        let position = self.position as *const _ as *const u8;
95        let base = base as *const _ as *const u8;
96        // safety: self.position is a subslice of base
97        unsafe { position.offset_from(base) as usize }
98    }
99
100    pub fn with_location(self, loc: &[u8]) -> InternalError<'_> {
101        InternalError {
102            position: loc,
103            kind: self.kind,
104        }
105    }
106
107    pub fn rebase(self, base: &[u8]) -> ParseError {
108        ParseError {
109            offset: self.offset(base),
110            kind: self.kind,
111        }
112    }
113}