1use core::alloc::Layout;
2use core::any::type_name;
3use core::fmt;
4use core::ops::{Range, RangeFrom};
5use core::str::Utf8Error;
6
7mod sealed {
8 pub trait Sealed {}
9 impl Sealed for () {}
10}
11
12pub trait IntoRepr
14where
15 Self: self::sealed::Sealed,
16{
17 #[doc(hidden)]
18 fn into_repr(self) -> Repr;
19}
20
21impl IntoRepr for () {
22 fn into_repr(self) -> Repr {
23 Repr {
24 kind: ReprKind::Unit,
25 }
26 }
27}
28
29macro_rules! impl_into_repr {
30 ($($ty:ty, $repr:ident),* $(,)?) => {
31 $(
32 impl self::sealed::Sealed for $ty {
33 }
34
35 impl IntoRepr for $ty {
36 fn into_repr(self) -> Repr {
37 Repr {
38 kind: ReprKind::$repr(self),
39 }
40 }
41 }
42 )*
43 }
44}
45
46impl_into_repr! {
47 u8, U8,
48 u16, U16,
49 u32, U32,
50 u64, U64,
51 u128, U128,
52 usize, Usize,
53 i8, I8,
54 i16, I16,
55 i32, I32,
56 i64, I64,
57 i128, I128,
58 isize, Isize,
59}
60
61#[derive(Debug)]
62#[cfg_attr(test, derive(PartialEq))]
63enum ReprKind {
64 Unit,
65 U8(u8),
66 U16(u16),
67 U32(u32),
68 U64(u64),
69 U128(u128),
70 I8(i8),
71 I16(i16),
72 I32(i32),
73 I64(i64),
74 I128(i128),
75 Usize(usize),
76 Isize(isize),
77}
78
79#[derive(Debug)]
81#[cfg_attr(test, derive(PartialEq))]
82#[non_exhaustive]
83pub struct Repr {
84 kind: ReprKind,
85}
86
87impl fmt::Display for Repr {
88 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
89 match &self.kind {
90 ReprKind::Unit => write!(f, "()"),
91 ReprKind::U8(value) => write!(f, "{value} (u8)"),
92 ReprKind::U16(value) => write!(f, "{value} (u16)"),
93 ReprKind::U32(value) => write!(f, "{value} (u32)"),
94 ReprKind::U64(value) => write!(f, "{value} (u64)"),
95 ReprKind::U128(value) => write!(f, "{value} (u128)"),
96 ReprKind::I8(value) => write!(f, "{value} (i8)"),
97 ReprKind::I16(value) => write!(f, "{value} (i16)"),
98 ReprKind::I32(value) => write!(f, "{value} (i32)"),
99 ReprKind::I64(value) => write!(f, "{value} (i64)"),
100 ReprKind::I128(value) => write!(f, "{value} (i128)"),
101 ReprKind::Usize(value) => write!(f, "{value} (usize)"),
102 ReprKind::Isize(value) => write!(f, "{value} (isize)"),
103 }
104 }
105}
106
107#[derive(Debug)]
109#[cfg_attr(test, derive(PartialEq))]
110pub struct CoerceError {
111 kind: CoerceErrorKind,
112}
113
114impl CoerceError {
115 #[inline]
116 pub(crate) const fn new(kind: CoerceErrorKind) -> Self {
117 Self { kind }
118 }
119}
120
121impl fmt::Display for CoerceError {
122 #[inline]
123 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
124 self.kind.fmt(f)
125 }
126}
127
128impl core::error::Error for CoerceError {}
129
130#[derive(Debug)]
131#[cfg_attr(test, derive(PartialEq))]
132#[non_exhaustive]
133pub(crate) enum CoerceErrorKind {
134 SliceLengthOverflow { item: usize, len: usize },
135 LengthOverflow { len: usize, size: usize },
136 InvalidLayout { size: Option<usize>, align: usize },
137 InvalidOffsetRange { offset: usize, end: usize },
138 Underflow { at: usize, len: usize },
139 Overflow { at: usize, len: usize },
140}
141
142impl fmt::Display for CoerceErrorKind {
143 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
144 match *self {
145 Self::SliceLengthOverflow { item, len } => {
146 write!(
147 f,
148 "Length overflowed when trying to take {item} elements of size {len}"
149 )
150 }
151 Self::LengthOverflow { len, size } => {
152 write!(
153 f,
154 "Length overflowed when trying to take {len} elements of size {size}"
155 )
156 }
157 Self::InvalidLayout {
158 size: Some(size),
159 align,
160 } => {
161 write!(f, "Invalid layout for size {size} and alignment {align}")
162 }
163 Self::InvalidLayout { size: None, align } => {
164 write!(
165 f,
166 "Invalid layout for overflowing size and alignment {align}"
167 )
168 }
169 Self::InvalidOffsetRange { offset, end } => {
170 write!(f, "Offset {offset} not in valid range 0-{end}")
171 }
172 Self::Underflow { at, len } => {
173 write!(f, "Arithmetic underflow calculating {at} - {len}")
174 }
175 Self::Overflow { at, len } => {
176 write!(f, "Arithmetic overflow calculating {at} + {len}")
177 }
178 }
179 }
180}
181
182#[derive(Debug)]
184#[cfg_attr(test, derive(PartialEq))]
185pub struct Error {
186 kind: ErrorKind,
187}
188
189impl Error {
190 #[inline]
191 pub(crate) const fn new(kind: ErrorKind) -> Self {
192 Self { kind }
193 }
194
195 #[inline(always)]
196 #[doc(hidden)]
197 pub fn __invalid_enum_discriminant<T>(discriminant: impl IntoRepr) -> Self {
198 Self::new(ErrorKind::InvalidDiscriminant {
199 name: type_name::<T>(),
200 discriminant: discriminant.into_repr(),
201 })
202 }
203}
204
205impl fmt::Display for Error {
206 #[inline]
207 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
208 self.kind.fmt(f)
209 }
210}
211
212impl core::error::Error for Error {}
213
214impl From<CoerceError> for Error {
215 #[inline]
216 fn from(error: CoerceError) -> Self {
217 Self::new(ErrorKind::CoerceError { error })
218 }
219}
220
221#[derive(Debug)]
222#[cfg_attr(test, derive(PartialEq))]
223#[non_exhaustive]
224pub(crate) enum ErrorKind {
225 Utf8Error {
226 error: Utf8Error,
227 },
228 CoerceError {
229 error: CoerceError,
230 },
231 AlignmentRangeMismatch {
232 addr: usize,
233 range: Range<usize>,
234 align: usize,
235 },
236 AlignmentRangeFromMismatch {
237 range: RangeFrom<usize>,
238 align: usize,
239 },
240 LayoutMismatch {
241 range: Range<usize>,
242 layout: Layout,
243 },
244 OutOfRangeBounds {
245 range: Range<usize>,
246 len: usize,
247 },
248 OutOfRangeFromBounds {
249 range: RangeFrom<usize>,
250 len: usize,
251 },
252 NonZeroZeroed {
253 range: Range<usize>,
254 },
255 IndexOutOfBounds {
256 index: usize,
257 len: usize,
258 },
259 ControlRangeOutOfBounds {
260 range: Range<usize>,
261 len: usize,
262 },
263 StrideOutOfBounds {
264 index: usize,
265 len: usize,
266 },
267 InvalidDiscriminant {
268 name: &'static str,
269 discriminant: Repr,
270 },
271 InvalidCharRepr {
272 repr: u32,
273 },
274 InvalidBoolRepr {
275 repr: u8,
276 },
277 StackOverflow {
278 capacity: usize,
279 },
280 #[cfg(feature = "alloc")]
281 CapacityError,
282 #[cfg(feature = "alloc")]
283 FailedPhf,
284}
285
286impl fmt::Display for ErrorKind {
287 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
288 match self {
289 ErrorKind::Utf8Error { error } => error.fmt(f),
290 ErrorKind::CoerceError { error } => error.fmt(f),
291 ErrorKind::AlignmentRangeMismatch { addr, range, align } => {
292 write!(
293 f,
294 "Alignment mismatch, expected alignment {align} for range {range:?} at address {addr:x}"
295 )
296 }
297 ErrorKind::AlignmentRangeFromMismatch { range, align } => {
298 write!(
299 f,
300 "Alignment mismatch, expected alignment {align} for range {range:?}"
301 )
302 }
303 ErrorKind::LayoutMismatch { range, layout } => {
304 write!(
305 f,
306 "Layout mismatch, expected {layout:?} for range {range:?}"
307 )
308 }
309 ErrorKind::OutOfRangeBounds { range, len } => {
310 write!(f, "Range {range:?} out of bound 0-{len}")
311 }
312 ErrorKind::OutOfRangeFromBounds { range, len } => {
313 write!(f, "Range {range:?} out of bound 0-{len}")
314 }
315 ErrorKind::NonZeroZeroed { range } => {
316 write!(f, "Expected non-zero range at {range:?}")
317 }
318 ErrorKind::IndexOutOfBounds { index, len } => {
319 write!(f, "Index {index} out of bound 0-{len}")
320 }
321 ErrorKind::ControlRangeOutOfBounds { range, len } => {
322 write!(f, "Control range {range:?} out of bound 0-{len}")
323 }
324 ErrorKind::StrideOutOfBounds { index, len } => {
325 write!(f, "Stride at index {index} out of bound 0-{len}")
326 }
327 ErrorKind::InvalidDiscriminant { name, discriminant } => {
328 write!(f, "Invalid discriminant {discriminant} for enum {name}")
329 }
330 ErrorKind::InvalidCharRepr { repr } => {
331 write!(f, "Invalid char representation {repr}")
332 }
333 ErrorKind::InvalidBoolRepr { repr } => {
334 write!(f, "Invalid bool representation {repr}")
335 }
336 ErrorKind::StackOverflow { capacity } => {
337 write!(f, "Stack with capacity {capacity} overflowed")
338 }
339 #[cfg(feature = "alloc")]
340 ErrorKind::CapacityError => {
341 write!(f, "Out of capacity")
342 }
343 #[cfg(feature = "alloc")]
344 ErrorKind::FailedPhf => {
345 write!(f, "Failed to construct perfect hash for map")
346 }
347 }
348 }
349}