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
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/// Indicates the representation that was tried to coerce into an enum.
80#[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/// Errors produced through coercion.
108#[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/// Müsli's zero copy error type.
183#[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}