serde_bare/
error.rs

1use core::fmt::{self, Debug, Display};
2use serde::{de, ser};
3use std::boxed::Box;
4
5pub type Result<T> = core::result::Result<T, Error>;
6
7pub struct Error {
8    inner: Box<ErrorImpl>,
9}
10
11impl Error {
12    fn new(inner: ErrorImpl) -> Self {
13        Self {
14            inner: Box::new(inner),
15        }
16    }
17
18    #[cfg(feature = "std")]
19    pub(crate) fn io(error: std::io::Error) -> Self {
20        Self::new(ErrorImpl::Io(error))
21    }
22
23    pub(crate) fn unexpected_eof() -> Self {
24        Self::new(ErrorImpl::UnexpectedEof)
25    }
26
27    pub(crate) fn any_unsupported() -> Self {
28        Self::new(ErrorImpl::AnyUnsupported)
29    }
30
31    pub(crate) fn invalid_utf8() -> Self {
32        Self::new(ErrorImpl::InvalidUtf8)
33    }
34
35    pub(crate) fn invalid_char() -> Self {
36        Self::new(ErrorImpl::InvalidChar)
37    }
38
39    pub(crate) fn sequence_length_required() -> Self {
40        Self::new(ErrorImpl::SequenceLengthRequired)
41    }
42
43    pub(crate) fn map_length_required() -> Self {
44        Self::new(ErrorImpl::MapLengthRequired)
45    }
46}
47
48#[cfg(feature = "std")]
49impl std::error::Error for Error {}
50
51impl Display for Error {
52    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
53        Display::fmt(&self.inner, f)
54    }
55}
56
57impl Debug for Error {
58    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
59        Debug::fmt(&self.inner, f)
60    }
61}
62
63impl ser::Error for Error {
64    fn custom<T: Display>(msg: T) -> Self {
65        Self {
66            inner: Box::new(ErrorImpl::Message(std::string::ToString::to_string(&msg))),
67        }
68    }
69}
70
71impl de::Error for Error {
72    fn custom<T: Display>(msg: T) -> Self {
73        Self {
74            inner: Box::new(ErrorImpl::Message(std::string::ToString::to_string(&msg))),
75        }
76    }
77}
78
79#[derive(Copy, Clone, PartialEq, Eq, Debug)]
80pub enum Category {
81    Io,
82    Data,
83    Eof,
84}
85
86impl Category {
87    /// Returns `true` if the category is [`Io`].
88    ///
89    /// [`Io`]: Category::Io
90    pub fn is_io(&self) -> bool {
91        matches!(self, Self::Io)
92    }
93
94    /// Returns `true` if the category is [`Data`].
95    ///
96    /// [`Data`]: Category::Data
97    pub fn is_data(&self) -> bool {
98        matches!(self, Self::Data)
99    }
100
101    /// Returns `true` if the category is [`Eof`].
102    ///
103    /// [`Eof`]: Category::Eof
104    pub fn is_eof(&self) -> bool {
105        matches!(self, Self::Eof)
106    }
107}
108
109impl Error {
110    pub fn classify(&self) -> Category {
111        match self.inner.as_ref() {
112            ErrorImpl::Message(_) => Category::Data,
113            #[cfg(feature = "std")]
114            ErrorImpl::Io(_) => Category::Io,
115            ErrorImpl::UnexpectedEof => Category::Eof,
116            ErrorImpl::AnyUnsupported
117            | ErrorImpl::InvalidUtf8
118            | ErrorImpl::InvalidChar
119            | ErrorImpl::SequenceLengthRequired
120            | ErrorImpl::MapLengthRequired => Category::Data,
121        }
122    }
123}
124
125#[cfg(feature = "std")]
126impl From<Error> for std::io::Error {
127    fn from(error: Error) -> Self {
128        if let ErrorImpl::Io(error) = *error.inner {
129            error
130        } else {
131            match error.classify() {
132                Category::Io => unreachable!(),
133                Category::Data => std::io::Error::new(std::io::ErrorKind::InvalidData, error),
134                Category::Eof => std::io::Error::new(std::io::ErrorKind::UnexpectedEof, error),
135            }
136        }
137    }
138}
139
140#[derive(Debug)]
141enum ErrorImpl {
142    Message(std::string::String),
143    #[cfg(feature = "std")]
144    Io(std::io::Error),
145    UnexpectedEof,
146
147    AnyUnsupported,
148
149    InvalidUtf8,
150    InvalidChar,
151
152    SequenceLengthRequired,
153    MapLengthRequired,
154}
155
156impl Display for ErrorImpl {
157    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
158        match self {
159            ErrorImpl::Message(msg) => formatter.write_str(msg),
160            #[cfg(feature = "std")]
161            ErrorImpl::Io(e) => Display::fmt(&e, formatter),
162            ErrorImpl::UnexpectedEof => formatter.write_str("unexpected end of input"),
163            ErrorImpl::AnyUnsupported => formatter.write_str("BARE does not support any"),
164            ErrorImpl::InvalidUtf8 => formatter.write_str("invalid utf-8 in string"),
165            ErrorImpl::InvalidChar => formatter.write_str("invalid unicode codepoint in char"),
166            ErrorImpl::SequenceLengthRequired => formatter.write_str("sequence length required"),
167            ErrorImpl::MapLengthRequired => formatter.write_str("map length required"),
168        }
169    }
170}