musli_zerocopy/
error.rs

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