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 pub fn is_io(&self) -> bool {
91 matches!(self, Self::Io)
92 }
93
94 pub fn is_data(&self) -> bool {
98 matches!(self, Self::Data)
99 }
100
101 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}