1use core::fmt::{Display, Formatter};
4use core::num::TryFromIntError;
5use core::ops::Range;
6use core::write;
7
8#[cfg(feature = "alloc")]
9use core::marker::{Send, Sync};
10
11#[cfg(feature = "alloc")]
12use alloc::boxed::Box;
13#[cfg(feature = "alloc")]
14use alloc::collections::TryReserveError;
15#[cfg(feature = "alloc")]
16use alloc::string::FromUtf8Error;
17
18pub type Result<T> = core::result::Result<T, Error>;
23
24#[derive(Debug)]
26pub struct Error {
27 kind: ErrorKind,
29
30 #[cfg(feature = "alloc")]
32 source: Option<Box<dyn core::error::Error + Send + Sync + 'static>>,
33}
34
35impl Error {
36 pub fn new(kind: ErrorKind) -> Self {
38 Self {
39 kind,
40 #[cfg(feature = "alloc")]
41 source: None,
42 }
43 }
44
45 #[cfg(feature = "alloc")]
47 pub fn new_with_source(kind: ErrorKind, source: impl core::error::Error + Send + Sync + 'static) -> Self {
48 Self {
49 kind,
50 source: Some(Box::new(source)),
51 }
52 }
53
54 pub fn kind(&self) -> &ErrorKind {
56 &self.kind
57 }
58}
59
60impl Display for Error {
61 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
62 self.kind.fmt(f)?;
64
65 #[cfg(feature = "alloc")]
66 if let Some(source) = &self.source {
68 f.write_str("\nError was caused by:\n")?;
69 source.fmt(f)?;
70 }
71
72 Ok(())
73 }
74}
75
76#[cfg(feature = "alloc")]
77impl core::error::Error for Error {
78 fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
79 self.source.as_deref().map(|e| e as &(dyn core::error::Error + 'static))
81 }
82}
83
84impl<T: Into<ErrorKind>> From<T> for Error {
85 fn from(value: T) -> Self {
87 Self::new(value.into())
88 }
89}
90
91#[derive(Debug)]
96#[non_exhaustive]
97pub enum ErrorKind {
98 UnexpectedEob {
100 requested: usize,
102 remaining: usize,
104 },
105
106 InvalidReservation {
110 buffer_len: usize,
112 reserved_range: Range<usize>,
114 },
115
116 #[cfg(feature = "alloc")]
121 AllocationError(TryReserveError),
122
123 AllocationLimitReached {
125 requested: usize,
126
127 remaining: usize,
128 },
129
130 InvalidData(InvalidDataErrorKind),
131}
132
133impl Display for ErrorKind {
134 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
135 match self {
136 Self::UnexpectedEob { requested, remaining } => {
137 write!(f, "unexpected end of buffer: attempted to read '{requested}' bytes from a buffer with only '{remaining}' bytes remaining")
138 }
139 Self::InvalidReservation {
140 buffer_len,
141 reserved_range,
142 } => {
143 let Range { start, end } = reserved_range;
144 write!(
145 f,
146 "invalid reservation: range '[{start}..{end})' does not fit within buffer of length '{buffer_len}'"
147 )
148 }
149 Self::InvalidData(inner) => inner.fmt(f),
150 _ => todo!(),
151 }
152 }
153}
154
155#[derive(Debug)]
156#[non_exhaustive]
157pub enum InvalidDataErrorKind {
158 IllegalValue { desc: &'static str, value: Option<i128> },
160
161 #[cfg(feature = "alloc")]
164 InvalidString(FromUtf8Error),
165
166 OutOfRange {
168 value: i128,
169 min: i128,
170 max: i128,
171 typename: &'static str,
172 },
173
174 #[cfg(feature = "alloc")]
176 DuplicateDictionaryKey,
177}
178
179impl Display for InvalidDataErrorKind {
180 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
181 match self {
182 Self::IllegalValue { desc, value } => {
183 if let Some(value) = value {
184 write!(f, "illegal value: {desc} (value: {value})")
185 } else {
186 write!(f, "illegal value: {desc}")
187 }
188 }
189
190 #[cfg(feature = "alloc")]
191 Self::InvalidString(inner) => inner.fmt(f),
192
193 Self::OutOfRange { value, min, max, typename } => {
194 write!(
195 f,
196 "value '{value}' is outside the allowed range for type '{typename}'; values must be within [{min}..{max}]"
197 )
198 }
199
200 #[cfg(feature = "alloc")]
201 Self::DuplicateDictionaryKey => write!(f, "duplicate dictionary key encountered"),
202 }
203 }
204}
205
206impl From<InvalidDataErrorKind> for ErrorKind {
207 fn from(value: InvalidDataErrorKind) -> Self {
208 ErrorKind::InvalidData(value)
209 }
210}
211
212impl From<TryFromIntError> for Error {
213 fn from(_: TryFromIntError) -> Self {
214 Error::from(InvalidDataErrorKind::IllegalValue {
215 desc: "failed to convert integer",
216 value: None,
217 })
218 }
219}
220
221#[cfg(feature = "alloc")]
222impl From<TryReserveError> for Error {
223 fn from(value: TryReserveError) -> Self {
224 Error::from(ErrorKind::AllocationError(value))
225 }
226}
227
228#[cfg(feature = "alloc")]
229impl From<FromUtf8Error> for Error {
230 fn from(value: FromUtf8Error) -> Self {
231 Error::from(InvalidDataErrorKind::InvalidString(value))
232 }
233}
234
235#[cfg(feature = "std")]
236impl From<Error> for std::io::Error {
237 fn from(value: Error) -> Self {
238 std::io::Error::other(value)
239 }
240}