xref: /linux/rust/zerocopy/src/error.rs (revision c37398010a05055e78cf0c75defb90df06c4e999)
1*c3739801SMiguel Ojeda // Copyright 2024 The Fuchsia Authors
2*c3739801SMiguel Ojeda //
3*c3739801SMiguel Ojeda // Licensed under the 2-Clause BSD License <LICENSE-BSD or
4*c3739801SMiguel Ojeda // https://opensource.org/license/bsd-2-clause>, Apache License, Version 2.0
5*c3739801SMiguel Ojeda // <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
6*c3739801SMiguel Ojeda // license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
7*c3739801SMiguel Ojeda // This file may not be copied, modified, or distributed except according to
8*c3739801SMiguel Ojeda // those terms.
9*c3739801SMiguel Ojeda 
10*c3739801SMiguel Ojeda //! Types related to error reporting.
11*c3739801SMiguel Ojeda //!
12*c3739801SMiguel Ojeda //! ## Single failure mode errors
13*c3739801SMiguel Ojeda //!
14*c3739801SMiguel Ojeda //! Generally speaking, zerocopy's conversions may fail for one of up to three
15*c3739801SMiguel Ojeda //! reasons:
16*c3739801SMiguel Ojeda //! - [`AlignmentError`]: the conversion source was improperly aligned
17*c3739801SMiguel Ojeda //! - [`SizeError`]: the conversion source was of incorrect size
18*c3739801SMiguel Ojeda //! - [`ValidityError`]: the conversion source contained invalid data
19*c3739801SMiguel Ojeda //!
20*c3739801SMiguel Ojeda //! Methods that only have one failure mode, like
21*c3739801SMiguel Ojeda //! [`FromBytes::read_from_bytes`], return that mode's corresponding error type
22*c3739801SMiguel Ojeda //! directly.
23*c3739801SMiguel Ojeda //!
24*c3739801SMiguel Ojeda //! ## Compound errors
25*c3739801SMiguel Ojeda //!
26*c3739801SMiguel Ojeda //! Conversion methods that have either two or three possible failure modes
27*c3739801SMiguel Ojeda //! return one of these error types:
28*c3739801SMiguel Ojeda //! - [`CastError`]: the error type of reference conversions
29*c3739801SMiguel Ojeda //! - [`TryCastError`]: the error type of fallible reference conversions
30*c3739801SMiguel Ojeda //! - [`TryReadError`]: the error type of fallible read conversions
31*c3739801SMiguel Ojeda //!
32*c3739801SMiguel Ojeda //! ## [`Unaligned`] destination types
33*c3739801SMiguel Ojeda //!
34*c3739801SMiguel Ojeda //! For [`Unaligned`] destination types, alignment errors are impossible. All
35*c3739801SMiguel Ojeda //! compound error types support infallibly discarding the alignment error via
36*c3739801SMiguel Ojeda //! [`From`] so long as `Dst: Unaligned`. For example, see [`<SizeError as
37*c3739801SMiguel Ojeda //! From<ConvertError>>::from`][size-error-from].
38*c3739801SMiguel Ojeda //!
39*c3739801SMiguel Ojeda //! [size-error-from]: struct.SizeError.html#method.from-1
40*c3739801SMiguel Ojeda //!
41*c3739801SMiguel Ojeda //! ## Accessing the conversion source
42*c3739801SMiguel Ojeda //!
43*c3739801SMiguel Ojeda //! All error types provide an `into_src` method that converts the error into
44*c3739801SMiguel Ojeda //! the source value underlying the failed conversion.
45*c3739801SMiguel Ojeda //!
46*c3739801SMiguel Ojeda //! ## Display formatting
47*c3739801SMiguel Ojeda //!
48*c3739801SMiguel Ojeda //! All error types provide a `Display` implementation that produces a
49*c3739801SMiguel Ojeda //! human-readable error message. When `debug_assertions` are enabled, these
50*c3739801SMiguel Ojeda //! error messages are verbose and may include potentially sensitive
51*c3739801SMiguel Ojeda //! information, including:
52*c3739801SMiguel Ojeda //!
53*c3739801SMiguel Ojeda //! - the names of the involved types
54*c3739801SMiguel Ojeda //! - the sizes of the involved types
55*c3739801SMiguel Ojeda //! - the addresses of the involved types
56*c3739801SMiguel Ojeda //! - the contents of the involved types
57*c3739801SMiguel Ojeda //!
58*c3739801SMiguel Ojeda //! When `debug_assertions` are disabled (as is default for `release` builds),
59*c3739801SMiguel Ojeda //! such potentially sensitive information is excluded.
60*c3739801SMiguel Ojeda //!
61*c3739801SMiguel Ojeda //! In the future, we may support manually configuring this behavior. If you are
62*c3739801SMiguel Ojeda //! interested in this feature, [let us know on GitHub][issue-1457] so we know
63*c3739801SMiguel Ojeda //! to prioritize it.
64*c3739801SMiguel Ojeda //!
65*c3739801SMiguel Ojeda //! [issue-1457]: https://github.com/google/zerocopy/issues/1457
66*c3739801SMiguel Ojeda //!
67*c3739801SMiguel Ojeda //! ## Validation order
68*c3739801SMiguel Ojeda //!
69*c3739801SMiguel Ojeda //! Our conversion methods typically check alignment, then size, then bit
70*c3739801SMiguel Ojeda //! validity. However, we do not guarantee that this is always the case, and
71*c3739801SMiguel Ojeda //! this behavior may change between releases.
72*c3739801SMiguel Ojeda //!
73*c3739801SMiguel Ojeda //! ## `Send`, `Sync`, and `'static`
74*c3739801SMiguel Ojeda //!
75*c3739801SMiguel Ojeda //! Our error types are `Send`, `Sync`, and `'static` when their `Src` parameter
76*c3739801SMiguel Ojeda //! is `Send`, `Sync`, or `'static`, respectively. This can cause issues when an
77*c3739801SMiguel Ojeda //! error is sent or synchronized across threads; e.g.:
78*c3739801SMiguel Ojeda //!
79*c3739801SMiguel Ojeda //! ```compile_fail,E0515
80*c3739801SMiguel Ojeda //! use zerocopy::*;
81*c3739801SMiguel Ojeda //!
82*c3739801SMiguel Ojeda //! let result: SizeError<&[u8], u32> = std::thread::spawn(|| {
83*c3739801SMiguel Ojeda //!     let source = &mut [0u8, 1, 2][..];
84*c3739801SMiguel Ojeda //!     // Try (and fail) to read a `u32` from `source`.
85*c3739801SMiguel Ojeda //!     u32::read_from_bytes(source).unwrap_err()
86*c3739801SMiguel Ojeda //! }).join().unwrap();
87*c3739801SMiguel Ojeda //! ```
88*c3739801SMiguel Ojeda //!
89*c3739801SMiguel Ojeda //! To work around this, use [`map_src`][CastError::map_src] to convert the
90*c3739801SMiguel Ojeda //! source parameter to an unproblematic type; e.g.:
91*c3739801SMiguel Ojeda //!
92*c3739801SMiguel Ojeda //! ```
93*c3739801SMiguel Ojeda //! use zerocopy::*;
94*c3739801SMiguel Ojeda //!
95*c3739801SMiguel Ojeda //! let result: SizeError<(), u32> = std::thread::spawn(|| {
96*c3739801SMiguel Ojeda //!     let source = &mut [0u8, 1, 2][..];
97*c3739801SMiguel Ojeda //!     // Try (and fail) to read a `u32` from `source`.
98*c3739801SMiguel Ojeda //!     u32::read_from_bytes(source).unwrap_err()
99*c3739801SMiguel Ojeda //!         // Erase the error source.
100*c3739801SMiguel Ojeda //!         .map_src(drop)
101*c3739801SMiguel Ojeda //! }).join().unwrap();
102*c3739801SMiguel Ojeda //! ```
103*c3739801SMiguel Ojeda //!
104*c3739801SMiguel Ojeda //! Alternatively, use `.to_string()` to eagerly convert the error into a
105*c3739801SMiguel Ojeda //! human-readable message; e.g.:
106*c3739801SMiguel Ojeda //!
107*c3739801SMiguel Ojeda //! ```
108*c3739801SMiguel Ojeda //! use zerocopy::*;
109*c3739801SMiguel Ojeda //!
110*c3739801SMiguel Ojeda //! let result: Result<u32, String> = std::thread::spawn(|| {
111*c3739801SMiguel Ojeda //!     let source = &mut [0u8, 1, 2][..];
112*c3739801SMiguel Ojeda //!     // Try (and fail) to read a `u32` from `source`.
113*c3739801SMiguel Ojeda //!     u32::read_from_bytes(source)
114*c3739801SMiguel Ojeda //!         // Eagerly render the error message.
115*c3739801SMiguel Ojeda //!         .map_err(|err| err.to_string())
116*c3739801SMiguel Ojeda //! }).join().unwrap();
117*c3739801SMiguel Ojeda //! ```
118*c3739801SMiguel Ojeda #[cfg(not(no_zerocopy_core_error_1_81_0))]
119*c3739801SMiguel Ojeda use core::error::Error;
120*c3739801SMiguel Ojeda use core::{
121*c3739801SMiguel Ojeda     convert::Infallible,
122*c3739801SMiguel Ojeda     fmt::{self, Debug, Write},
123*c3739801SMiguel Ojeda     ops::Deref,
124*c3739801SMiguel Ojeda };
125*c3739801SMiguel Ojeda #[cfg(all(no_zerocopy_core_error_1_81_0, any(feature = "std", test)))]
126*c3739801SMiguel Ojeda use std::error::Error;
127*c3739801SMiguel Ojeda 
128*c3739801SMiguel Ojeda use crate::{util::SendSyncPhantomData, KnownLayout, TryFromBytes, Unaligned};
129*c3739801SMiguel Ojeda #[cfg(doc)]
130*c3739801SMiguel Ojeda use crate::{FromBytes, Ref};
131*c3739801SMiguel Ojeda 
132*c3739801SMiguel Ojeda /// Zerocopy's generic error type.
133*c3739801SMiguel Ojeda ///
134*c3739801SMiguel Ojeda /// Generally speaking, zerocopy's conversions may fail for one of up to three
135*c3739801SMiguel Ojeda /// reasons:
136*c3739801SMiguel Ojeda /// - [`AlignmentError`]: the conversion source was improperly aligned
137*c3739801SMiguel Ojeda /// - [`SizeError`]: the conversion source was of incorrect size
138*c3739801SMiguel Ojeda /// - [`ValidityError`]: the conversion source contained invalid data
139*c3739801SMiguel Ojeda ///
140*c3739801SMiguel Ojeda /// However, not all conversions produce all errors. For instance,
141*c3739801SMiguel Ojeda /// [`FromBytes::ref_from_bytes`] may fail due to alignment or size issues, but
142*c3739801SMiguel Ojeda /// not validity issues. This generic error type captures these
143*c3739801SMiguel Ojeda /// (im)possibilities via parameterization: `A` is parameterized with
144*c3739801SMiguel Ojeda /// [`AlignmentError`], `S` is parameterized with [`SizeError`], and `V` is
145*c3739801SMiguel Ojeda /// parameterized with [`Infallible`].
146*c3739801SMiguel Ojeda ///
147*c3739801SMiguel Ojeda /// Zerocopy never uses this type directly in its API. Rather, we provide three
148*c3739801SMiguel Ojeda /// pre-parameterized aliases:
149*c3739801SMiguel Ojeda /// - [`CastError`]: the error type of reference conversions
150*c3739801SMiguel Ojeda /// - [`TryCastError`]: the error type of fallible reference conversions
151*c3739801SMiguel Ojeda /// - [`TryReadError`]: the error type of fallible read conversions
152*c3739801SMiguel Ojeda #[derive(PartialEq, Eq, Clone)]
153*c3739801SMiguel Ojeda pub enum ConvertError<A, S, V> {
154*c3739801SMiguel Ojeda     /// The conversion source was improperly aligned.
155*c3739801SMiguel Ojeda     Alignment(A),
156*c3739801SMiguel Ojeda     /// The conversion source was of incorrect size.
157*c3739801SMiguel Ojeda     Size(S),
158*c3739801SMiguel Ojeda     /// The conversion source contained invalid data.
159*c3739801SMiguel Ojeda     Validity(V),
160*c3739801SMiguel Ojeda }
161*c3739801SMiguel Ojeda 
162*c3739801SMiguel Ojeda impl<Src, Dst: ?Sized + Unaligned, S, V> From<ConvertError<AlignmentError<Src, Dst>, S, V>>
163*c3739801SMiguel Ojeda     for ConvertError<Infallible, S, V>
164*c3739801SMiguel Ojeda {
165*c3739801SMiguel Ojeda     /// Infallibly discards the alignment error from this `ConvertError` since
166*c3739801SMiguel Ojeda     /// `Dst` is unaligned.
167*c3739801SMiguel Ojeda     ///
168*c3739801SMiguel Ojeda     /// Since [`Dst: Unaligned`], it is impossible to encounter an alignment
169*c3739801SMiguel Ojeda     /// error. This method permits discarding that alignment error infallibly
170*c3739801SMiguel Ojeda     /// and replacing it with [`Infallible`].
171*c3739801SMiguel Ojeda     ///
172*c3739801SMiguel Ojeda     /// [`Dst: Unaligned`]: crate::Unaligned
173*c3739801SMiguel Ojeda     ///
174*c3739801SMiguel Ojeda     /// # Examples
175*c3739801SMiguel Ojeda     ///
176*c3739801SMiguel Ojeda     /// ```
177*c3739801SMiguel Ojeda     /// use core::convert::Infallible;
178*c3739801SMiguel Ojeda     /// use zerocopy::*;
179*c3739801SMiguel Ojeda     /// # use zerocopy_derive::*;
180*c3739801SMiguel Ojeda     ///
181*c3739801SMiguel Ojeda     /// #[derive(TryFromBytes, KnownLayout, Unaligned, Immutable)]
182*c3739801SMiguel Ojeda     /// #[repr(C, packed)]
183*c3739801SMiguel Ojeda     /// struct Bools {
184*c3739801SMiguel Ojeda     ///     one: bool,
185*c3739801SMiguel Ojeda     ///     two: bool,
186*c3739801SMiguel Ojeda     ///     many: [bool],
187*c3739801SMiguel Ojeda     /// }
188*c3739801SMiguel Ojeda     ///
189*c3739801SMiguel Ojeda     /// impl Bools {
190*c3739801SMiguel Ojeda     ///     fn parse(bytes: &[u8]) -> Result<&Bools, AlignedTryCastError<&[u8], Bools>> {
191*c3739801SMiguel Ojeda     ///         // Since `Bools: Unaligned`, we can infallibly discard
192*c3739801SMiguel Ojeda     ///         // the alignment error.
193*c3739801SMiguel Ojeda     ///         Bools::try_ref_from_bytes(bytes).map_err(Into::into)
194*c3739801SMiguel Ojeda     ///     }
195*c3739801SMiguel Ojeda     /// }
196*c3739801SMiguel Ojeda     /// ```
197*c3739801SMiguel Ojeda     #[inline]
198*c3739801SMiguel Ojeda     fn from(err: ConvertError<AlignmentError<Src, Dst>, S, V>) -> ConvertError<Infallible, S, V> {
199*c3739801SMiguel Ojeda         match err {
200*c3739801SMiguel Ojeda             ConvertError::Alignment(e) => {
201*c3739801SMiguel Ojeda                 #[allow(unreachable_code)]
202*c3739801SMiguel Ojeda                 return ConvertError::Alignment(Infallible::from(e));
203*c3739801SMiguel Ojeda             }
204*c3739801SMiguel Ojeda             ConvertError::Size(e) => ConvertError::Size(e),
205*c3739801SMiguel Ojeda             ConvertError::Validity(e) => ConvertError::Validity(e),
206*c3739801SMiguel Ojeda         }
207*c3739801SMiguel Ojeda     }
208*c3739801SMiguel Ojeda }
209*c3739801SMiguel Ojeda 
210*c3739801SMiguel Ojeda impl<A: fmt::Debug, S: fmt::Debug, V: fmt::Debug> fmt::Debug for ConvertError<A, S, V> {
211*c3739801SMiguel Ojeda     #[inline]
212*c3739801SMiguel Ojeda     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
213*c3739801SMiguel Ojeda         match self {
214*c3739801SMiguel Ojeda             Self::Alignment(e) => f.debug_tuple("Alignment").field(e).finish(),
215*c3739801SMiguel Ojeda             Self::Size(e) => f.debug_tuple("Size").field(e).finish(),
216*c3739801SMiguel Ojeda             Self::Validity(e) => f.debug_tuple("Validity").field(e).finish(),
217*c3739801SMiguel Ojeda         }
218*c3739801SMiguel Ojeda     }
219*c3739801SMiguel Ojeda }
220*c3739801SMiguel Ojeda 
221*c3739801SMiguel Ojeda /// Produces a human-readable error message.
222*c3739801SMiguel Ojeda ///
223*c3739801SMiguel Ojeda /// The message differs between debug and release builds. When
224*c3739801SMiguel Ojeda /// `debug_assertions` are enabled, this message is verbose and includes
225*c3739801SMiguel Ojeda /// potentially sensitive information.
226*c3739801SMiguel Ojeda impl<A: fmt::Display, S: fmt::Display, V: fmt::Display> fmt::Display for ConvertError<A, S, V> {
227*c3739801SMiguel Ojeda     #[inline]
228*c3739801SMiguel Ojeda     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
229*c3739801SMiguel Ojeda         match self {
230*c3739801SMiguel Ojeda             Self::Alignment(e) => e.fmt(f),
231*c3739801SMiguel Ojeda             Self::Size(e) => e.fmt(f),
232*c3739801SMiguel Ojeda             Self::Validity(e) => e.fmt(f),
233*c3739801SMiguel Ojeda         }
234*c3739801SMiguel Ojeda     }
235*c3739801SMiguel Ojeda }
236*c3739801SMiguel Ojeda 
237*c3739801SMiguel Ojeda #[cfg(any(not(no_zerocopy_core_error_1_81_0), feature = "std", test))]
238*c3739801SMiguel Ojeda #[cfg_attr(doc_cfg, doc(cfg(all(rust = "1.81.0", feature = "std"))))]
239*c3739801SMiguel Ojeda impl<A, S, V> Error for ConvertError<A, S, V>
240*c3739801SMiguel Ojeda where
241*c3739801SMiguel Ojeda     A: fmt::Display + fmt::Debug,
242*c3739801SMiguel Ojeda     S: fmt::Display + fmt::Debug,
243*c3739801SMiguel Ojeda     V: fmt::Display + fmt::Debug,
244*c3739801SMiguel Ojeda {
245*c3739801SMiguel Ojeda }
246*c3739801SMiguel Ojeda 
247*c3739801SMiguel Ojeda /// The error emitted if the conversion source is improperly aligned.
248*c3739801SMiguel Ojeda pub struct AlignmentError<Src, Dst: ?Sized> {
249*c3739801SMiguel Ojeda     /// The source value involved in the conversion.
250*c3739801SMiguel Ojeda     src: Src,
251*c3739801SMiguel Ojeda     /// The inner destination type involved in the conversion.
252*c3739801SMiguel Ojeda     ///
253*c3739801SMiguel Ojeda     /// INVARIANT: An `AlignmentError` may only be constructed if `Dst`'s
254*c3739801SMiguel Ojeda     /// alignment requirement is greater than one.
255*c3739801SMiguel Ojeda     _dst: SendSyncPhantomData<Dst>,
256*c3739801SMiguel Ojeda }
257*c3739801SMiguel Ojeda 
258*c3739801SMiguel Ojeda impl<Src, Dst: ?Sized> AlignmentError<Src, Dst> {
259*c3739801SMiguel Ojeda     /// # Safety
260*c3739801SMiguel Ojeda     ///
261*c3739801SMiguel Ojeda     /// The caller must ensure that `Dst`'s alignment requirement is greater
262*c3739801SMiguel Ojeda     /// than one.
263*c3739801SMiguel Ojeda     pub(crate) unsafe fn new_unchecked(src: Src) -> Self {
264*c3739801SMiguel Ojeda         // INVARIANT: The caller guarantees that `Dst`'s alignment requirement
265*c3739801SMiguel Ojeda         // is greater than one.
266*c3739801SMiguel Ojeda         Self { src, _dst: SendSyncPhantomData::default() }
267*c3739801SMiguel Ojeda     }
268*c3739801SMiguel Ojeda 
269*c3739801SMiguel Ojeda     /// Produces the source underlying the failed conversion.
270*c3739801SMiguel Ojeda     #[inline]
271*c3739801SMiguel Ojeda     pub fn into_src(self) -> Src {
272*c3739801SMiguel Ojeda         self.src
273*c3739801SMiguel Ojeda     }
274*c3739801SMiguel Ojeda 
275*c3739801SMiguel Ojeda     pub(crate) fn with_src<NewSrc>(self, new_src: NewSrc) -> AlignmentError<NewSrc, Dst> {
276*c3739801SMiguel Ojeda         // INVARIANT: `with_src` doesn't change the type of `Dst`, so the
277*c3739801SMiguel Ojeda         // invariant that `Dst`'s alignment requirement is greater than one is
278*c3739801SMiguel Ojeda         // preserved.
279*c3739801SMiguel Ojeda         AlignmentError { src: new_src, _dst: SendSyncPhantomData::default() }
280*c3739801SMiguel Ojeda     }
281*c3739801SMiguel Ojeda 
282*c3739801SMiguel Ojeda     /// Maps the source value associated with the conversion error.
283*c3739801SMiguel Ojeda     ///
284*c3739801SMiguel Ojeda     /// This can help mitigate [issues with `Send`, `Sync` and `'static`
285*c3739801SMiguel Ojeda     /// bounds][self#send-sync-and-static].
286*c3739801SMiguel Ojeda     ///
287*c3739801SMiguel Ojeda     /// # Examples
288*c3739801SMiguel Ojeda     ///
289*c3739801SMiguel Ojeda     /// ```
290*c3739801SMiguel Ojeda     /// use zerocopy::*;
291*c3739801SMiguel Ojeda     ///
292*c3739801SMiguel Ojeda     /// let unaligned = Unalign::new(0u16);
293*c3739801SMiguel Ojeda     ///
294*c3739801SMiguel Ojeda     /// // Attempt to deref `unaligned`. This might fail with an alignment error.
295*c3739801SMiguel Ojeda     /// let maybe_n: Result<&u16, AlignmentError<&Unalign<u16>, u16>> = unaligned.try_deref();
296*c3739801SMiguel Ojeda     ///
297*c3739801SMiguel Ojeda     /// // Map the error's source to its address as a usize.
298*c3739801SMiguel Ojeda     /// let maybe_n: Result<&u16, AlignmentError<usize, u16>> = maybe_n.map_err(|err| {
299*c3739801SMiguel Ojeda     ///     err.map_src(|src| src as *const _ as usize)
300*c3739801SMiguel Ojeda     /// });
301*c3739801SMiguel Ojeda     /// ```
302*c3739801SMiguel Ojeda     #[inline]
303*c3739801SMiguel Ojeda     pub fn map_src<NewSrc>(self, f: impl FnOnce(Src) -> NewSrc) -> AlignmentError<NewSrc, Dst> {
304*c3739801SMiguel Ojeda         AlignmentError { src: f(self.src), _dst: SendSyncPhantomData::default() }
305*c3739801SMiguel Ojeda     }
306*c3739801SMiguel Ojeda 
307*c3739801SMiguel Ojeda     pub(crate) fn into<S, V>(self) -> ConvertError<Self, S, V> {
308*c3739801SMiguel Ojeda         ConvertError::Alignment(self)
309*c3739801SMiguel Ojeda     }
310*c3739801SMiguel Ojeda 
311*c3739801SMiguel Ojeda     /// Format extra details for a verbose, human-readable error message.
312*c3739801SMiguel Ojeda     ///
313*c3739801SMiguel Ojeda     /// This formatting may include potentially sensitive information.
314*c3739801SMiguel Ojeda     fn display_verbose_extras(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
315*c3739801SMiguel Ojeda     where
316*c3739801SMiguel Ojeda         Src: Deref,
317*c3739801SMiguel Ojeda         Dst: KnownLayout,
318*c3739801SMiguel Ojeda     {
319*c3739801SMiguel Ojeda         #[allow(clippy::as_conversions)]
320*c3739801SMiguel Ojeda         let addr = self.src.deref() as *const _ as *const ();
321*c3739801SMiguel Ojeda         let addr_align = 2usize.pow((crate::util::AsAddress::addr(addr)).trailing_zeros());
322*c3739801SMiguel Ojeda 
323*c3739801SMiguel Ojeda         f.write_str("\n\nSource type: ")?;
324*c3739801SMiguel Ojeda         f.write_str(core::any::type_name::<Src>())?;
325*c3739801SMiguel Ojeda 
326*c3739801SMiguel Ojeda         f.write_str("\nSource address: ")?;
327*c3739801SMiguel Ojeda         addr.fmt(f)?;
328*c3739801SMiguel Ojeda         f.write_str(" (a multiple of ")?;
329*c3739801SMiguel Ojeda         addr_align.fmt(f)?;
330*c3739801SMiguel Ojeda         f.write_str(")")?;
331*c3739801SMiguel Ojeda 
332*c3739801SMiguel Ojeda         f.write_str("\nDestination type: ")?;
333*c3739801SMiguel Ojeda         f.write_str(core::any::type_name::<Dst>())?;
334*c3739801SMiguel Ojeda 
335*c3739801SMiguel Ojeda         f.write_str("\nDestination alignment: ")?;
336*c3739801SMiguel Ojeda         <Dst as KnownLayout>::LAYOUT.align.get().fmt(f)?;
337*c3739801SMiguel Ojeda 
338*c3739801SMiguel Ojeda         Ok(())
339*c3739801SMiguel Ojeda     }
340*c3739801SMiguel Ojeda }
341*c3739801SMiguel Ojeda 
342*c3739801SMiguel Ojeda impl<Src: Clone, Dst: ?Sized> Clone for AlignmentError<Src, Dst> {
343*c3739801SMiguel Ojeda     #[inline]
344*c3739801SMiguel Ojeda     fn clone(&self) -> Self {
345*c3739801SMiguel Ojeda         Self { src: self.src.clone(), _dst: SendSyncPhantomData::default() }
346*c3739801SMiguel Ojeda     }
347*c3739801SMiguel Ojeda }
348*c3739801SMiguel Ojeda 
349*c3739801SMiguel Ojeda impl<Src: PartialEq, Dst: ?Sized> PartialEq for AlignmentError<Src, Dst> {
350*c3739801SMiguel Ojeda     #[inline]
351*c3739801SMiguel Ojeda     fn eq(&self, other: &Self) -> bool {
352*c3739801SMiguel Ojeda         self.src == other.src
353*c3739801SMiguel Ojeda     }
354*c3739801SMiguel Ojeda }
355*c3739801SMiguel Ojeda 
356*c3739801SMiguel Ojeda impl<Src: Eq, Dst: ?Sized> Eq for AlignmentError<Src, Dst> {}
357*c3739801SMiguel Ojeda 
358*c3739801SMiguel Ojeda impl<Src, Dst: ?Sized + Unaligned> From<AlignmentError<Src, Dst>> for Infallible {
359*c3739801SMiguel Ojeda     #[inline(always)]
360*c3739801SMiguel Ojeda     fn from(_: AlignmentError<Src, Dst>) -> Infallible {
361*c3739801SMiguel Ojeda         // SAFETY: `AlignmentError`s can only be constructed when `Dst`'s
362*c3739801SMiguel Ojeda         // alignment requirement is greater than one. In this block, `Dst:
363*c3739801SMiguel Ojeda         // Unaligned`, which means that its alignment requirement is equal to
364*c3739801SMiguel Ojeda         // one. Thus, it's not possible to reach here at runtime.
365*c3739801SMiguel Ojeda         unsafe { core::hint::unreachable_unchecked() }
366*c3739801SMiguel Ojeda     }
367*c3739801SMiguel Ojeda }
368*c3739801SMiguel Ojeda 
369*c3739801SMiguel Ojeda #[cfg(test)]
370*c3739801SMiguel Ojeda impl<Src, Dst> AlignmentError<Src, Dst> {
371*c3739801SMiguel Ojeda     // A convenience constructor so that test code doesn't need to write
372*c3739801SMiguel Ojeda     // `unsafe`.
373*c3739801SMiguel Ojeda     fn new_checked(src: Src) -> AlignmentError<Src, Dst> {
374*c3739801SMiguel Ojeda         assert_ne!(core::mem::align_of::<Dst>(), 1);
375*c3739801SMiguel Ojeda         // SAFETY: The preceding assertion guarantees that `Dst`'s alignment
376*c3739801SMiguel Ojeda         // requirement is greater than one.
377*c3739801SMiguel Ojeda         unsafe { AlignmentError::new_unchecked(src) }
378*c3739801SMiguel Ojeda     }
379*c3739801SMiguel Ojeda }
380*c3739801SMiguel Ojeda 
381*c3739801SMiguel Ojeda impl<Src, Dst: ?Sized> fmt::Debug for AlignmentError<Src, Dst> {
382*c3739801SMiguel Ojeda     #[inline]
383*c3739801SMiguel Ojeda     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
384*c3739801SMiguel Ojeda         f.debug_struct("AlignmentError").finish()
385*c3739801SMiguel Ojeda     }
386*c3739801SMiguel Ojeda }
387*c3739801SMiguel Ojeda 
388*c3739801SMiguel Ojeda /// Produces a human-readable error message.
389*c3739801SMiguel Ojeda ///
390*c3739801SMiguel Ojeda /// The message differs between debug and release builds. When
391*c3739801SMiguel Ojeda /// `debug_assertions` are enabled, this message is verbose and includes
392*c3739801SMiguel Ojeda /// potentially sensitive information.
393*c3739801SMiguel Ojeda impl<Src, Dst: ?Sized> fmt::Display for AlignmentError<Src, Dst>
394*c3739801SMiguel Ojeda where
395*c3739801SMiguel Ojeda     Src: Deref,
396*c3739801SMiguel Ojeda     Dst: KnownLayout,
397*c3739801SMiguel Ojeda {
398*c3739801SMiguel Ojeda     #[inline]
399*c3739801SMiguel Ojeda     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
400*c3739801SMiguel Ojeda         f.write_str("The conversion failed because the address of the source is not a multiple of the alignment of the destination type.")?;
401*c3739801SMiguel Ojeda 
402*c3739801SMiguel Ojeda         if cfg!(debug_assertions) {
403*c3739801SMiguel Ojeda             self.display_verbose_extras(f)
404*c3739801SMiguel Ojeda         } else {
405*c3739801SMiguel Ojeda             Ok(())
406*c3739801SMiguel Ojeda         }
407*c3739801SMiguel Ojeda     }
408*c3739801SMiguel Ojeda }
409*c3739801SMiguel Ojeda 
410*c3739801SMiguel Ojeda #[cfg(any(not(no_zerocopy_core_error_1_81_0), feature = "std", test))]
411*c3739801SMiguel Ojeda #[cfg_attr(doc_cfg, doc(cfg(all(rust = "1.81.0", feature = "std"))))]
412*c3739801SMiguel Ojeda impl<Src, Dst: ?Sized> Error for AlignmentError<Src, Dst>
413*c3739801SMiguel Ojeda where
414*c3739801SMiguel Ojeda     Src: Deref,
415*c3739801SMiguel Ojeda     Dst: KnownLayout,
416*c3739801SMiguel Ojeda {
417*c3739801SMiguel Ojeda }
418*c3739801SMiguel Ojeda 
419*c3739801SMiguel Ojeda impl<Src, Dst: ?Sized, S, V> From<AlignmentError<Src, Dst>>
420*c3739801SMiguel Ojeda     for ConvertError<AlignmentError<Src, Dst>, S, V>
421*c3739801SMiguel Ojeda {
422*c3739801SMiguel Ojeda     #[inline(always)]
423*c3739801SMiguel Ojeda     fn from(err: AlignmentError<Src, Dst>) -> Self {
424*c3739801SMiguel Ojeda         Self::Alignment(err)
425*c3739801SMiguel Ojeda     }
426*c3739801SMiguel Ojeda }
427*c3739801SMiguel Ojeda 
428*c3739801SMiguel Ojeda /// The error emitted if the conversion source is of incorrect size.
429*c3739801SMiguel Ojeda pub struct SizeError<Src, Dst: ?Sized> {
430*c3739801SMiguel Ojeda     /// The source value involved in the conversion.
431*c3739801SMiguel Ojeda     src: Src,
432*c3739801SMiguel Ojeda     /// The inner destination type involved in the conversion.
433*c3739801SMiguel Ojeda     _dst: SendSyncPhantomData<Dst>,
434*c3739801SMiguel Ojeda }
435*c3739801SMiguel Ojeda 
436*c3739801SMiguel Ojeda impl<Src, Dst: ?Sized> SizeError<Src, Dst> {
437*c3739801SMiguel Ojeda     pub(crate) fn new(src: Src) -> Self {
438*c3739801SMiguel Ojeda         Self { src, _dst: SendSyncPhantomData::default() }
439*c3739801SMiguel Ojeda     }
440*c3739801SMiguel Ojeda 
441*c3739801SMiguel Ojeda     /// Produces the source underlying the failed conversion.
442*c3739801SMiguel Ojeda     #[inline]
443*c3739801SMiguel Ojeda     pub fn into_src(self) -> Src {
444*c3739801SMiguel Ojeda         self.src
445*c3739801SMiguel Ojeda     }
446*c3739801SMiguel Ojeda 
447*c3739801SMiguel Ojeda     /// Sets the source value associated with the conversion error.
448*c3739801SMiguel Ojeda     pub(crate) fn with_src<NewSrc>(self, new_src: NewSrc) -> SizeError<NewSrc, Dst> {
449*c3739801SMiguel Ojeda         SizeError { src: new_src, _dst: SendSyncPhantomData::default() }
450*c3739801SMiguel Ojeda     }
451*c3739801SMiguel Ojeda 
452*c3739801SMiguel Ojeda     /// Maps the source value associated with the conversion error.
453*c3739801SMiguel Ojeda     ///
454*c3739801SMiguel Ojeda     /// This can help mitigate [issues with `Send`, `Sync` and `'static`
455*c3739801SMiguel Ojeda     /// bounds][self#send-sync-and-static].
456*c3739801SMiguel Ojeda     ///
457*c3739801SMiguel Ojeda     /// # Examples
458*c3739801SMiguel Ojeda     ///
459*c3739801SMiguel Ojeda     /// ```
460*c3739801SMiguel Ojeda     /// use zerocopy::*;
461*c3739801SMiguel Ojeda     ///
462*c3739801SMiguel Ojeda     /// let source: [u8; 3] = [0, 1, 2];
463*c3739801SMiguel Ojeda     ///
464*c3739801SMiguel Ojeda     /// // Try to read a `u32` from `source`. This will fail because there are insufficient
465*c3739801SMiguel Ojeda     /// // bytes in `source`.
466*c3739801SMiguel Ojeda     /// let maybe_u32: Result<u32, SizeError<&[u8], u32>> = u32::read_from_bytes(&source[..]);
467*c3739801SMiguel Ojeda     ///
468*c3739801SMiguel Ojeda     /// // Map the error's source to its size.
469*c3739801SMiguel Ojeda     /// let maybe_u32: Result<u32, SizeError<usize, u32>> = maybe_u32.map_err(|err| {
470*c3739801SMiguel Ojeda     ///     err.map_src(|src| src.len())
471*c3739801SMiguel Ojeda     /// });
472*c3739801SMiguel Ojeda     /// ```
473*c3739801SMiguel Ojeda     #[inline]
474*c3739801SMiguel Ojeda     pub fn map_src<NewSrc>(self, f: impl FnOnce(Src) -> NewSrc) -> SizeError<NewSrc, Dst> {
475*c3739801SMiguel Ojeda         SizeError { src: f(self.src), _dst: SendSyncPhantomData::default() }
476*c3739801SMiguel Ojeda     }
477*c3739801SMiguel Ojeda 
478*c3739801SMiguel Ojeda     /// Sets the destination type associated with the conversion error.
479*c3739801SMiguel Ojeda     pub(crate) fn with_dst<NewDst: ?Sized>(self) -> SizeError<Src, NewDst> {
480*c3739801SMiguel Ojeda         SizeError { src: self.src, _dst: SendSyncPhantomData::default() }
481*c3739801SMiguel Ojeda     }
482*c3739801SMiguel Ojeda 
483*c3739801SMiguel Ojeda     /// Converts the error into a general [`ConvertError`].
484*c3739801SMiguel Ojeda     pub(crate) fn into<A, V>(self) -> ConvertError<A, Self, V> {
485*c3739801SMiguel Ojeda         ConvertError::Size(self)
486*c3739801SMiguel Ojeda     }
487*c3739801SMiguel Ojeda 
488*c3739801SMiguel Ojeda     /// Format extra details for a verbose, human-readable error message.
489*c3739801SMiguel Ojeda     ///
490*c3739801SMiguel Ojeda     /// This formatting may include potentially sensitive information.
491*c3739801SMiguel Ojeda     fn display_verbose_extras(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
492*c3739801SMiguel Ojeda     where
493*c3739801SMiguel Ojeda         Src: Deref,
494*c3739801SMiguel Ojeda         Dst: KnownLayout,
495*c3739801SMiguel Ojeda     {
496*c3739801SMiguel Ojeda         // include the source type
497*c3739801SMiguel Ojeda         f.write_str("\nSource type: ")?;
498*c3739801SMiguel Ojeda         f.write_str(core::any::type_name::<Src>())?;
499*c3739801SMiguel Ojeda 
500*c3739801SMiguel Ojeda         // include the source.deref() size
501*c3739801SMiguel Ojeda         let src_size = core::mem::size_of_val(&*self.src);
502*c3739801SMiguel Ojeda         f.write_str("\nSource size: ")?;
503*c3739801SMiguel Ojeda         src_size.fmt(f)?;
504*c3739801SMiguel Ojeda         f.write_str(" byte")?;
505*c3739801SMiguel Ojeda         if src_size != 1 {
506*c3739801SMiguel Ojeda             f.write_char('s')?;
507*c3739801SMiguel Ojeda         }
508*c3739801SMiguel Ojeda 
509*c3739801SMiguel Ojeda         // if `Dst` is `Sized`, include the `Dst` size
510*c3739801SMiguel Ojeda         if let crate::SizeInfo::Sized { size } = Dst::LAYOUT.size_info {
511*c3739801SMiguel Ojeda             f.write_str("\nDestination size: ")?;
512*c3739801SMiguel Ojeda             size.fmt(f)?;
513*c3739801SMiguel Ojeda             f.write_str(" byte")?;
514*c3739801SMiguel Ojeda             if size != 1 {
515*c3739801SMiguel Ojeda                 f.write_char('s')?;
516*c3739801SMiguel Ojeda             }
517*c3739801SMiguel Ojeda         }
518*c3739801SMiguel Ojeda 
519*c3739801SMiguel Ojeda         // include the destination type
520*c3739801SMiguel Ojeda         f.write_str("\nDestination type: ")?;
521*c3739801SMiguel Ojeda         f.write_str(core::any::type_name::<Dst>())?;
522*c3739801SMiguel Ojeda 
523*c3739801SMiguel Ojeda         Ok(())
524*c3739801SMiguel Ojeda     }
525*c3739801SMiguel Ojeda }
526*c3739801SMiguel Ojeda 
527*c3739801SMiguel Ojeda impl<Src: Clone, Dst: ?Sized> Clone for SizeError<Src, Dst> {
528*c3739801SMiguel Ojeda     #[inline]
529*c3739801SMiguel Ojeda     fn clone(&self) -> Self {
530*c3739801SMiguel Ojeda         Self { src: self.src.clone(), _dst: SendSyncPhantomData::default() }
531*c3739801SMiguel Ojeda     }
532*c3739801SMiguel Ojeda }
533*c3739801SMiguel Ojeda 
534*c3739801SMiguel Ojeda impl<Src: PartialEq, Dst: ?Sized> PartialEq for SizeError<Src, Dst> {
535*c3739801SMiguel Ojeda     #[inline]
536*c3739801SMiguel Ojeda     fn eq(&self, other: &Self) -> bool {
537*c3739801SMiguel Ojeda         self.src == other.src
538*c3739801SMiguel Ojeda     }
539*c3739801SMiguel Ojeda }
540*c3739801SMiguel Ojeda 
541*c3739801SMiguel Ojeda impl<Src: Eq, Dst: ?Sized> Eq for SizeError<Src, Dst> {}
542*c3739801SMiguel Ojeda 
543*c3739801SMiguel Ojeda impl<Src, Dst: ?Sized> fmt::Debug for SizeError<Src, Dst> {
544*c3739801SMiguel Ojeda     #[inline]
545*c3739801SMiguel Ojeda     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
546*c3739801SMiguel Ojeda         f.debug_struct("SizeError").finish()
547*c3739801SMiguel Ojeda     }
548*c3739801SMiguel Ojeda }
549*c3739801SMiguel Ojeda 
550*c3739801SMiguel Ojeda /// Produces a human-readable error message.
551*c3739801SMiguel Ojeda ///
552*c3739801SMiguel Ojeda /// The message differs between debug and release builds. When
553*c3739801SMiguel Ojeda /// `debug_assertions` are enabled, this message is verbose and includes
554*c3739801SMiguel Ojeda /// potentially sensitive information.
555*c3739801SMiguel Ojeda impl<Src, Dst: ?Sized> fmt::Display for SizeError<Src, Dst>
556*c3739801SMiguel Ojeda where
557*c3739801SMiguel Ojeda     Src: Deref,
558*c3739801SMiguel Ojeda     Dst: KnownLayout,
559*c3739801SMiguel Ojeda {
560*c3739801SMiguel Ojeda     #[inline]
561*c3739801SMiguel Ojeda     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
562*c3739801SMiguel Ojeda         f.write_str("The conversion failed because the source was incorrectly sized to complete the conversion into the destination type.")?;
563*c3739801SMiguel Ojeda         if cfg!(debug_assertions) {
564*c3739801SMiguel Ojeda             f.write_str("\n")?;
565*c3739801SMiguel Ojeda             self.display_verbose_extras(f)?;
566*c3739801SMiguel Ojeda         }
567*c3739801SMiguel Ojeda         Ok(())
568*c3739801SMiguel Ojeda     }
569*c3739801SMiguel Ojeda }
570*c3739801SMiguel Ojeda 
571*c3739801SMiguel Ojeda #[cfg(any(not(no_zerocopy_core_error_1_81_0), feature = "std", test))]
572*c3739801SMiguel Ojeda #[cfg_attr(doc_cfg, doc(cfg(all(rust = "1.81.0", feature = "std"))))]
573*c3739801SMiguel Ojeda impl<Src, Dst: ?Sized> Error for SizeError<Src, Dst>
574*c3739801SMiguel Ojeda where
575*c3739801SMiguel Ojeda     Src: Deref,
576*c3739801SMiguel Ojeda     Dst: KnownLayout,
577*c3739801SMiguel Ojeda {
578*c3739801SMiguel Ojeda }
579*c3739801SMiguel Ojeda 
580*c3739801SMiguel Ojeda impl<Src, Dst: ?Sized, A, V> From<SizeError<Src, Dst>> for ConvertError<A, SizeError<Src, Dst>, V> {
581*c3739801SMiguel Ojeda     #[inline(always)]
582*c3739801SMiguel Ojeda     fn from(err: SizeError<Src, Dst>) -> Self {
583*c3739801SMiguel Ojeda         Self::Size(err)
584*c3739801SMiguel Ojeda     }
585*c3739801SMiguel Ojeda }
586*c3739801SMiguel Ojeda 
587*c3739801SMiguel Ojeda /// The error emitted if the conversion source contains invalid data.
588*c3739801SMiguel Ojeda pub struct ValidityError<Src, Dst: ?Sized + TryFromBytes> {
589*c3739801SMiguel Ojeda     /// The source value involved in the conversion.
590*c3739801SMiguel Ojeda     pub(crate) src: Src,
591*c3739801SMiguel Ojeda     /// The inner destination type involved in the conversion.
592*c3739801SMiguel Ojeda     _dst: SendSyncPhantomData<Dst>,
593*c3739801SMiguel Ojeda }
594*c3739801SMiguel Ojeda 
595*c3739801SMiguel Ojeda impl<Src, Dst: ?Sized + TryFromBytes> ValidityError<Src, Dst> {
596*c3739801SMiguel Ojeda     pub(crate) fn new(src: Src) -> Self {
597*c3739801SMiguel Ojeda         Self { src, _dst: SendSyncPhantomData::default() }
598*c3739801SMiguel Ojeda     }
599*c3739801SMiguel Ojeda 
600*c3739801SMiguel Ojeda     /// Produces the source underlying the failed conversion.
601*c3739801SMiguel Ojeda     #[inline]
602*c3739801SMiguel Ojeda     pub fn into_src(self) -> Src {
603*c3739801SMiguel Ojeda         self.src
604*c3739801SMiguel Ojeda     }
605*c3739801SMiguel Ojeda 
606*c3739801SMiguel Ojeda     /// Maps the source value associated with the conversion error.
607*c3739801SMiguel Ojeda     ///
608*c3739801SMiguel Ojeda     /// This can help mitigate [issues with `Send`, `Sync` and `'static`
609*c3739801SMiguel Ojeda     /// bounds][self#send-sync-and-static].
610*c3739801SMiguel Ojeda     ///
611*c3739801SMiguel Ojeda     /// # Examples
612*c3739801SMiguel Ojeda     ///
613*c3739801SMiguel Ojeda     /// ```
614*c3739801SMiguel Ojeda     /// use zerocopy::*;
615*c3739801SMiguel Ojeda     ///
616*c3739801SMiguel Ojeda     /// let source: u8 = 42;
617*c3739801SMiguel Ojeda     ///
618*c3739801SMiguel Ojeda     /// // Try to transmute the `source` to a `bool`. This will fail.
619*c3739801SMiguel Ojeda     /// let maybe_bool: Result<bool, ValidityError<u8, bool>> = try_transmute!(source);
620*c3739801SMiguel Ojeda     ///
621*c3739801SMiguel Ojeda     /// // Drop the error's source.
622*c3739801SMiguel Ojeda     /// let maybe_bool: Result<bool, ValidityError<(), bool>> = maybe_bool.map_err(|err| {
623*c3739801SMiguel Ojeda     ///     err.map_src(drop)
624*c3739801SMiguel Ojeda     /// });
625*c3739801SMiguel Ojeda     /// ```
626*c3739801SMiguel Ojeda     #[inline]
627*c3739801SMiguel Ojeda     pub fn map_src<NewSrc>(self, f: impl FnOnce(Src) -> NewSrc) -> ValidityError<NewSrc, Dst> {
628*c3739801SMiguel Ojeda         ValidityError { src: f(self.src), _dst: SendSyncPhantomData::default() }
629*c3739801SMiguel Ojeda     }
630*c3739801SMiguel Ojeda 
631*c3739801SMiguel Ojeda     /// Converts the error into a general [`ConvertError`].
632*c3739801SMiguel Ojeda     pub(crate) fn into<A, S>(self) -> ConvertError<A, S, Self> {
633*c3739801SMiguel Ojeda         ConvertError::Validity(self)
634*c3739801SMiguel Ojeda     }
635*c3739801SMiguel Ojeda 
636*c3739801SMiguel Ojeda     /// Format extra details for a verbose, human-readable error message.
637*c3739801SMiguel Ojeda     ///
638*c3739801SMiguel Ojeda     /// This formatting may include potentially sensitive information.
639*c3739801SMiguel Ojeda     fn display_verbose_extras(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
640*c3739801SMiguel Ojeda     where
641*c3739801SMiguel Ojeda         Dst: KnownLayout,
642*c3739801SMiguel Ojeda     {
643*c3739801SMiguel Ojeda         f.write_str("Destination type: ")?;
644*c3739801SMiguel Ojeda         f.write_str(core::any::type_name::<Dst>())?;
645*c3739801SMiguel Ojeda         Ok(())
646*c3739801SMiguel Ojeda     }
647*c3739801SMiguel Ojeda }
648*c3739801SMiguel Ojeda 
649*c3739801SMiguel Ojeda impl<Src: Clone, Dst: ?Sized + TryFromBytes> Clone for ValidityError<Src, Dst> {
650*c3739801SMiguel Ojeda     #[inline]
651*c3739801SMiguel Ojeda     fn clone(&self) -> Self {
652*c3739801SMiguel Ojeda         Self { src: self.src.clone(), _dst: SendSyncPhantomData::default() }
653*c3739801SMiguel Ojeda     }
654*c3739801SMiguel Ojeda }
655*c3739801SMiguel Ojeda 
656*c3739801SMiguel Ojeda // SAFETY: `ValidityError` contains a single `Self::Inner = Src`, and no other
657*c3739801SMiguel Ojeda // non-ZST fields. `map` passes ownership of `self`'s sole `Self::Inner` to `f`.
658*c3739801SMiguel Ojeda unsafe impl<Src, NewSrc, Dst> crate::pointer::TryWithError<NewSrc>
659*c3739801SMiguel Ojeda     for crate::ValidityError<Src, Dst>
660*c3739801SMiguel Ojeda where
661*c3739801SMiguel Ojeda     Dst: TryFromBytes + ?Sized,
662*c3739801SMiguel Ojeda {
663*c3739801SMiguel Ojeda     type Inner = Src;
664*c3739801SMiguel Ojeda     type Mapped = crate::ValidityError<NewSrc, Dst>;
665*c3739801SMiguel Ojeda     #[inline]
666*c3739801SMiguel Ojeda     fn map<F: FnOnce(Src) -> NewSrc>(self, f: F) -> Self::Mapped {
667*c3739801SMiguel Ojeda         self.map_src(f)
668*c3739801SMiguel Ojeda     }
669*c3739801SMiguel Ojeda }
670*c3739801SMiguel Ojeda 
671*c3739801SMiguel Ojeda impl<Src: PartialEq, Dst: ?Sized + TryFromBytes> PartialEq for ValidityError<Src, Dst> {
672*c3739801SMiguel Ojeda     #[inline]
673*c3739801SMiguel Ojeda     fn eq(&self, other: &Self) -> bool {
674*c3739801SMiguel Ojeda         self.src == other.src
675*c3739801SMiguel Ojeda     }
676*c3739801SMiguel Ojeda }
677*c3739801SMiguel Ojeda 
678*c3739801SMiguel Ojeda impl<Src: Eq, Dst: ?Sized + TryFromBytes> Eq for ValidityError<Src, Dst> {}
679*c3739801SMiguel Ojeda 
680*c3739801SMiguel Ojeda impl<Src, Dst: ?Sized + TryFromBytes> fmt::Debug for ValidityError<Src, Dst> {
681*c3739801SMiguel Ojeda     #[inline]
682*c3739801SMiguel Ojeda     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
683*c3739801SMiguel Ojeda         f.debug_struct("ValidityError").finish()
684*c3739801SMiguel Ojeda     }
685*c3739801SMiguel Ojeda }
686*c3739801SMiguel Ojeda 
687*c3739801SMiguel Ojeda /// Produces a human-readable error message.
688*c3739801SMiguel Ojeda ///
689*c3739801SMiguel Ojeda /// The message differs between debug and release builds. When
690*c3739801SMiguel Ojeda /// `debug_assertions` are enabled, this message is verbose and includes
691*c3739801SMiguel Ojeda /// potentially sensitive information.
692*c3739801SMiguel Ojeda impl<Src, Dst: ?Sized> fmt::Display for ValidityError<Src, Dst>
693*c3739801SMiguel Ojeda where
694*c3739801SMiguel Ojeda     Dst: KnownLayout + TryFromBytes,
695*c3739801SMiguel Ojeda {
696*c3739801SMiguel Ojeda     #[inline]
697*c3739801SMiguel Ojeda     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
698*c3739801SMiguel Ojeda         f.write_str("The conversion failed because the source bytes are not a valid value of the destination type.")?;
699*c3739801SMiguel Ojeda         if cfg!(debug_assertions) {
700*c3739801SMiguel Ojeda             f.write_str("\n\n")?;
701*c3739801SMiguel Ojeda             self.display_verbose_extras(f)?;
702*c3739801SMiguel Ojeda         }
703*c3739801SMiguel Ojeda         Ok(())
704*c3739801SMiguel Ojeda     }
705*c3739801SMiguel Ojeda }
706*c3739801SMiguel Ojeda 
707*c3739801SMiguel Ojeda #[cfg(any(not(no_zerocopy_core_error_1_81_0), feature = "std", test))]
708*c3739801SMiguel Ojeda #[cfg_attr(doc_cfg, doc(cfg(all(rust = "1.81.0", feature = "std"))))]
709*c3739801SMiguel Ojeda impl<Src, Dst: ?Sized> Error for ValidityError<Src, Dst> where Dst: KnownLayout + TryFromBytes {}
710*c3739801SMiguel Ojeda 
711*c3739801SMiguel Ojeda impl<Src, Dst: ?Sized + TryFromBytes, A, S> From<ValidityError<Src, Dst>>
712*c3739801SMiguel Ojeda     for ConvertError<A, S, ValidityError<Src, Dst>>
713*c3739801SMiguel Ojeda {
714*c3739801SMiguel Ojeda     #[inline(always)]
715*c3739801SMiguel Ojeda     fn from(err: ValidityError<Src, Dst>) -> Self {
716*c3739801SMiguel Ojeda         Self::Validity(err)
717*c3739801SMiguel Ojeda     }
718*c3739801SMiguel Ojeda }
719*c3739801SMiguel Ojeda 
720*c3739801SMiguel Ojeda /// The error type of reference conversions.
721*c3739801SMiguel Ojeda ///
722*c3739801SMiguel Ojeda /// Reference conversions, like [`FromBytes::ref_from_bytes`] may emit
723*c3739801SMiguel Ojeda /// [alignment](AlignmentError) and [size](SizeError) errors.
724*c3739801SMiguel Ojeda // Bounds on generic parameters are not enforced in type aliases, but they do
725*c3739801SMiguel Ojeda // appear in rustdoc.
726*c3739801SMiguel Ojeda #[allow(type_alias_bounds)]
727*c3739801SMiguel Ojeda pub type CastError<Src, Dst: ?Sized> =
728*c3739801SMiguel Ojeda     ConvertError<AlignmentError<Src, Dst>, SizeError<Src, Dst>, Infallible>;
729*c3739801SMiguel Ojeda 
730*c3739801SMiguel Ojeda impl<Src, Dst: ?Sized> CastError<Src, Dst> {
731*c3739801SMiguel Ojeda     /// Produces the source underlying the failed conversion.
732*c3739801SMiguel Ojeda     #[inline]
733*c3739801SMiguel Ojeda     pub fn into_src(self) -> Src {
734*c3739801SMiguel Ojeda         match self {
735*c3739801SMiguel Ojeda             Self::Alignment(e) => e.src,
736*c3739801SMiguel Ojeda             Self::Size(e) => e.src,
737*c3739801SMiguel Ojeda             Self::Validity(i) => match i {},
738*c3739801SMiguel Ojeda         }
739*c3739801SMiguel Ojeda     }
740*c3739801SMiguel Ojeda 
741*c3739801SMiguel Ojeda     /// Sets the source value associated with the conversion error.
742*c3739801SMiguel Ojeda     pub(crate) fn with_src<NewSrc>(self, new_src: NewSrc) -> CastError<NewSrc, Dst> {
743*c3739801SMiguel Ojeda         match self {
744*c3739801SMiguel Ojeda             Self::Alignment(e) => CastError::Alignment(e.with_src(new_src)),
745*c3739801SMiguel Ojeda             Self::Size(e) => CastError::Size(e.with_src(new_src)),
746*c3739801SMiguel Ojeda             Self::Validity(i) => match i {},
747*c3739801SMiguel Ojeda         }
748*c3739801SMiguel Ojeda     }
749*c3739801SMiguel Ojeda 
750*c3739801SMiguel Ojeda     /// Maps the source value associated with the conversion error.
751*c3739801SMiguel Ojeda     ///
752*c3739801SMiguel Ojeda     /// This can help mitigate [issues with `Send`, `Sync` and `'static`
753*c3739801SMiguel Ojeda     /// bounds][self#send-sync-and-static].
754*c3739801SMiguel Ojeda     ///
755*c3739801SMiguel Ojeda     /// # Examples
756*c3739801SMiguel Ojeda     ///
757*c3739801SMiguel Ojeda     /// ```
758*c3739801SMiguel Ojeda     /// use zerocopy::*;
759*c3739801SMiguel Ojeda     ///
760*c3739801SMiguel Ojeda     /// let source: [u8; 3] = [0, 1, 2];
761*c3739801SMiguel Ojeda     ///
762*c3739801SMiguel Ojeda     /// // Try to read a `u32` from `source`. This will fail because there are insufficient
763*c3739801SMiguel Ojeda     /// // bytes in `source`.
764*c3739801SMiguel Ojeda     /// let maybe_u32: Result<&u32, CastError<&[u8], u32>> = u32::ref_from_bytes(&source[..]);
765*c3739801SMiguel Ojeda     ///
766*c3739801SMiguel Ojeda     /// // Map the error's source to its size and address.
767*c3739801SMiguel Ojeda     /// let maybe_u32: Result<&u32, CastError<(usize, usize), u32>> = maybe_u32.map_err(|err| {
768*c3739801SMiguel Ojeda     ///     err.map_src(|src| (src.len(), src.as_ptr() as usize))
769*c3739801SMiguel Ojeda     /// });
770*c3739801SMiguel Ojeda     /// ```
771*c3739801SMiguel Ojeda     #[inline]
772*c3739801SMiguel Ojeda     pub fn map_src<NewSrc>(self, f: impl FnOnce(Src) -> NewSrc) -> CastError<NewSrc, Dst> {
773*c3739801SMiguel Ojeda         match self {
774*c3739801SMiguel Ojeda             Self::Alignment(e) => CastError::Alignment(e.map_src(f)),
775*c3739801SMiguel Ojeda             Self::Size(e) => CastError::Size(e.map_src(f)),
776*c3739801SMiguel Ojeda             Self::Validity(i) => match i {},
777*c3739801SMiguel Ojeda         }
778*c3739801SMiguel Ojeda     }
779*c3739801SMiguel Ojeda 
780*c3739801SMiguel Ojeda     /// Converts the error into a general [`ConvertError`].
781*c3739801SMiguel Ojeda     pub(crate) fn into(self) -> TryCastError<Src, Dst>
782*c3739801SMiguel Ojeda     where
783*c3739801SMiguel Ojeda         Dst: TryFromBytes,
784*c3739801SMiguel Ojeda     {
785*c3739801SMiguel Ojeda         match self {
786*c3739801SMiguel Ojeda             Self::Alignment(e) => TryCastError::Alignment(e),
787*c3739801SMiguel Ojeda             Self::Size(e) => TryCastError::Size(e),
788*c3739801SMiguel Ojeda             Self::Validity(i) => match i {},
789*c3739801SMiguel Ojeda         }
790*c3739801SMiguel Ojeda     }
791*c3739801SMiguel Ojeda }
792*c3739801SMiguel Ojeda 
793*c3739801SMiguel Ojeda // SAFETY: `CastError` is either a single `AlignmentError` or a single
794*c3739801SMiguel Ojeda // `SizeError`. In either case, it contains a single `Self::Inner = Src`, and no
795*c3739801SMiguel Ojeda // other non-ZST fields. `map` passes ownership of `self`'s sole `Self::Inner`
796*c3739801SMiguel Ojeda // to `f`.
797*c3739801SMiguel Ojeda unsafe impl<Src, NewSrc, Dst> crate::pointer::TryWithError<NewSrc> for crate::CastError<Src, Dst>
798*c3739801SMiguel Ojeda where
799*c3739801SMiguel Ojeda     Dst: ?Sized,
800*c3739801SMiguel Ojeda {
801*c3739801SMiguel Ojeda     type Inner = Src;
802*c3739801SMiguel Ojeda     type Mapped = crate::CastError<NewSrc, Dst>;
803*c3739801SMiguel Ojeda 
804*c3739801SMiguel Ojeda     #[inline]
805*c3739801SMiguel Ojeda     fn map<F: FnOnce(Src) -> NewSrc>(self, f: F) -> Self::Mapped {
806*c3739801SMiguel Ojeda         self.map_src(f)
807*c3739801SMiguel Ojeda     }
808*c3739801SMiguel Ojeda }
809*c3739801SMiguel Ojeda 
810*c3739801SMiguel Ojeda impl<Src, Dst: ?Sized + Unaligned> From<CastError<Src, Dst>> for SizeError<Src, Dst> {
811*c3739801SMiguel Ojeda     /// Infallibly extracts the [`SizeError`] from this `CastError` since `Dst`
812*c3739801SMiguel Ojeda     /// is unaligned.
813*c3739801SMiguel Ojeda     ///
814*c3739801SMiguel Ojeda     /// Since [`Dst: Unaligned`], it is impossible to encounter an alignment
815*c3739801SMiguel Ojeda     /// error, and so the only error that can be encountered at runtime is a
816*c3739801SMiguel Ojeda     /// [`SizeError`]. This method permits extracting that `SizeError`
817*c3739801SMiguel Ojeda     /// infallibly.
818*c3739801SMiguel Ojeda     ///
819*c3739801SMiguel Ojeda     /// [`Dst: Unaligned`]: crate::Unaligned
820*c3739801SMiguel Ojeda     ///
821*c3739801SMiguel Ojeda     /// # Examples
822*c3739801SMiguel Ojeda     ///
823*c3739801SMiguel Ojeda     /// ```rust
824*c3739801SMiguel Ojeda     /// use zerocopy::*;
825*c3739801SMiguel Ojeda     /// # use zerocopy_derive::*;
826*c3739801SMiguel Ojeda     ///
827*c3739801SMiguel Ojeda     /// #[derive(FromBytes, IntoBytes, KnownLayout, Immutable, Unaligned)]
828*c3739801SMiguel Ojeda     /// #[repr(C)]
829*c3739801SMiguel Ojeda     /// struct UdpHeader {
830*c3739801SMiguel Ojeda     ///     src_port: [u8; 2],
831*c3739801SMiguel Ojeda     ///     dst_port: [u8; 2],
832*c3739801SMiguel Ojeda     ///     length: [u8; 2],
833*c3739801SMiguel Ojeda     ///     checksum: [u8; 2],
834*c3739801SMiguel Ojeda     /// }
835*c3739801SMiguel Ojeda     ///
836*c3739801SMiguel Ojeda     /// #[derive(FromBytes, IntoBytes, KnownLayout, Immutable, Unaligned)]
837*c3739801SMiguel Ojeda     /// #[repr(C, packed)]
838*c3739801SMiguel Ojeda     /// struct UdpPacket {
839*c3739801SMiguel Ojeda     ///     header: UdpHeader,
840*c3739801SMiguel Ojeda     ///     body: [u8],
841*c3739801SMiguel Ojeda     /// }
842*c3739801SMiguel Ojeda     ///
843*c3739801SMiguel Ojeda     /// impl UdpPacket {
844*c3739801SMiguel Ojeda     ///     pub fn parse(bytes: &[u8]) -> Result<&UdpPacket, SizeError<&[u8], UdpPacket>> {
845*c3739801SMiguel Ojeda     ///         // Since `UdpPacket: Unaligned`, we can map the `CastError` to a `SizeError`.
846*c3739801SMiguel Ojeda     ///         UdpPacket::ref_from_bytes(bytes).map_err(Into::into)
847*c3739801SMiguel Ojeda     ///     }
848*c3739801SMiguel Ojeda     /// }
849*c3739801SMiguel Ojeda     /// ```
850*c3739801SMiguel Ojeda     #[inline(always)]
851*c3739801SMiguel Ojeda     fn from(err: CastError<Src, Dst>) -> SizeError<Src, Dst> {
852*c3739801SMiguel Ojeda         match err {
853*c3739801SMiguel Ojeda             #[allow(unreachable_code)]
854*c3739801SMiguel Ojeda             CastError::Alignment(e) => match Infallible::from(e) {},
855*c3739801SMiguel Ojeda             CastError::Size(e) => e,
856*c3739801SMiguel Ojeda             CastError::Validity(i) => match i {},
857*c3739801SMiguel Ojeda         }
858*c3739801SMiguel Ojeda     }
859*c3739801SMiguel Ojeda }
860*c3739801SMiguel Ojeda 
861*c3739801SMiguel Ojeda /// The error type of fallible reference conversions.
862*c3739801SMiguel Ojeda ///
863*c3739801SMiguel Ojeda /// Fallible reference conversions, like [`TryFromBytes::try_ref_from_bytes`]
864*c3739801SMiguel Ojeda /// may emit [alignment](AlignmentError), [size](SizeError), and
865*c3739801SMiguel Ojeda /// [validity](ValidityError) errors.
866*c3739801SMiguel Ojeda // Bounds on generic parameters are not enforced in type aliases, but they do
867*c3739801SMiguel Ojeda // appear in rustdoc.
868*c3739801SMiguel Ojeda #[allow(type_alias_bounds)]
869*c3739801SMiguel Ojeda pub type TryCastError<Src, Dst: ?Sized + TryFromBytes> =
870*c3739801SMiguel Ojeda     ConvertError<AlignmentError<Src, Dst>, SizeError<Src, Dst>, ValidityError<Src, Dst>>;
871*c3739801SMiguel Ojeda 
872*c3739801SMiguel Ojeda // FIXME(#1139): Remove the `TryFromBytes` here and in other downstream
873*c3739801SMiguel Ojeda // locations (all the way to `ValidityError`) if we determine it's not necessary
874*c3739801SMiguel Ojeda // for rich validity errors.
875*c3739801SMiguel Ojeda impl<Src, Dst: ?Sized + TryFromBytes> TryCastError<Src, Dst> {
876*c3739801SMiguel Ojeda     /// Produces the source underlying the failed conversion.
877*c3739801SMiguel Ojeda     #[inline]
878*c3739801SMiguel Ojeda     pub fn into_src(self) -> Src {
879*c3739801SMiguel Ojeda         match self {
880*c3739801SMiguel Ojeda             Self::Alignment(e) => e.src,
881*c3739801SMiguel Ojeda             Self::Size(e) => e.src,
882*c3739801SMiguel Ojeda             Self::Validity(e) => e.src,
883*c3739801SMiguel Ojeda         }
884*c3739801SMiguel Ojeda     }
885*c3739801SMiguel Ojeda 
886*c3739801SMiguel Ojeda     /// Maps the source value associated with the conversion error.
887*c3739801SMiguel Ojeda     ///
888*c3739801SMiguel Ojeda     /// This can help mitigate [issues with `Send`, `Sync` and `'static`
889*c3739801SMiguel Ojeda     /// bounds][self#send-sync-and-static].
890*c3739801SMiguel Ojeda     ///
891*c3739801SMiguel Ojeda     /// # Examples
892*c3739801SMiguel Ojeda     ///
893*c3739801SMiguel Ojeda     /// ```
894*c3739801SMiguel Ojeda     /// use core::num::NonZeroU32;
895*c3739801SMiguel Ojeda     /// use zerocopy::*;
896*c3739801SMiguel Ojeda     ///
897*c3739801SMiguel Ojeda     /// let source: [u8; 3] = [0, 0, 0];
898*c3739801SMiguel Ojeda     ///
899*c3739801SMiguel Ojeda     /// // Try to read a `NonZeroU32` from `source`.
900*c3739801SMiguel Ojeda     /// let maybe_u32: Result<&NonZeroU32, TryCastError<&[u8], NonZeroU32>>
901*c3739801SMiguel Ojeda     ///     = NonZeroU32::try_ref_from_bytes(&source[..]);
902*c3739801SMiguel Ojeda     ///
903*c3739801SMiguel Ojeda     /// // Map the error's source to its size and address.
904*c3739801SMiguel Ojeda     /// let maybe_u32: Result<&NonZeroU32, TryCastError<(usize, usize), NonZeroU32>> =
905*c3739801SMiguel Ojeda     ///     maybe_u32.map_err(|err| {
906*c3739801SMiguel Ojeda     ///         err.map_src(|src| (src.len(), src.as_ptr() as usize))
907*c3739801SMiguel Ojeda     ///     });
908*c3739801SMiguel Ojeda     /// ```
909*c3739801SMiguel Ojeda     #[inline]
910*c3739801SMiguel Ojeda     pub fn map_src<NewSrc>(self, f: impl FnOnce(Src) -> NewSrc) -> TryCastError<NewSrc, Dst> {
911*c3739801SMiguel Ojeda         match self {
912*c3739801SMiguel Ojeda             Self::Alignment(e) => TryCastError::Alignment(e.map_src(f)),
913*c3739801SMiguel Ojeda             Self::Size(e) => TryCastError::Size(e.map_src(f)),
914*c3739801SMiguel Ojeda             Self::Validity(e) => TryCastError::Validity(e.map_src(f)),
915*c3739801SMiguel Ojeda         }
916*c3739801SMiguel Ojeda     }
917*c3739801SMiguel Ojeda }
918*c3739801SMiguel Ojeda 
919*c3739801SMiguel Ojeda impl<Src, Dst: ?Sized + TryFromBytes> From<CastError<Src, Dst>> for TryCastError<Src, Dst> {
920*c3739801SMiguel Ojeda     #[inline]
921*c3739801SMiguel Ojeda     fn from(value: CastError<Src, Dst>) -> Self {
922*c3739801SMiguel Ojeda         match value {
923*c3739801SMiguel Ojeda             CastError::Alignment(e) => Self::Alignment(e),
924*c3739801SMiguel Ojeda             CastError::Size(e) => Self::Size(e),
925*c3739801SMiguel Ojeda             CastError::Validity(i) => match i {},
926*c3739801SMiguel Ojeda         }
927*c3739801SMiguel Ojeda     }
928*c3739801SMiguel Ojeda }
929*c3739801SMiguel Ojeda 
930*c3739801SMiguel Ojeda /// The error type of fallible read-conversions.
931*c3739801SMiguel Ojeda ///
932*c3739801SMiguel Ojeda /// Fallible read-conversions, like [`TryFromBytes::try_read_from_bytes`] may
933*c3739801SMiguel Ojeda /// emit [size](SizeError) and [validity](ValidityError) errors, but not
934*c3739801SMiguel Ojeda /// alignment errors.
935*c3739801SMiguel Ojeda // Bounds on generic parameters are not enforced in type aliases, but they do
936*c3739801SMiguel Ojeda // appear in rustdoc.
937*c3739801SMiguel Ojeda #[allow(type_alias_bounds)]
938*c3739801SMiguel Ojeda pub type TryReadError<Src, Dst: ?Sized + TryFromBytes> =
939*c3739801SMiguel Ojeda     ConvertError<Infallible, SizeError<Src, Dst>, ValidityError<Src, Dst>>;
940*c3739801SMiguel Ojeda 
941*c3739801SMiguel Ojeda impl<Src, Dst: ?Sized + TryFromBytes> TryReadError<Src, Dst> {
942*c3739801SMiguel Ojeda     /// Produces the source underlying the failed conversion.
943*c3739801SMiguel Ojeda     #[inline]
944*c3739801SMiguel Ojeda     pub fn into_src(self) -> Src {
945*c3739801SMiguel Ojeda         match self {
946*c3739801SMiguel Ojeda             Self::Alignment(i) => match i {},
947*c3739801SMiguel Ojeda             Self::Size(e) => e.src,
948*c3739801SMiguel Ojeda             Self::Validity(e) => e.src,
949*c3739801SMiguel Ojeda         }
950*c3739801SMiguel Ojeda     }
951*c3739801SMiguel Ojeda 
952*c3739801SMiguel Ojeda     /// Maps the source value associated with the conversion error.
953*c3739801SMiguel Ojeda     ///
954*c3739801SMiguel Ojeda     /// This can help mitigate [issues with `Send`, `Sync` and `'static`
955*c3739801SMiguel Ojeda     /// bounds][self#send-sync-and-static].
956*c3739801SMiguel Ojeda     ///
957*c3739801SMiguel Ojeda     /// # Examples
958*c3739801SMiguel Ojeda     ///
959*c3739801SMiguel Ojeda     /// ```
960*c3739801SMiguel Ojeda     /// use core::num::NonZeroU32;
961*c3739801SMiguel Ojeda     /// use zerocopy::*;
962*c3739801SMiguel Ojeda     ///
963*c3739801SMiguel Ojeda     /// let source: [u8; 3] = [0, 0, 0];
964*c3739801SMiguel Ojeda     ///
965*c3739801SMiguel Ojeda     /// // Try to read a `NonZeroU32` from `source`.
966*c3739801SMiguel Ojeda     /// let maybe_u32: Result<NonZeroU32, TryReadError<&[u8], NonZeroU32>>
967*c3739801SMiguel Ojeda     ///     = NonZeroU32::try_read_from_bytes(&source[..]);
968*c3739801SMiguel Ojeda     ///
969*c3739801SMiguel Ojeda     /// // Map the error's source to its size.
970*c3739801SMiguel Ojeda     /// let maybe_u32: Result<NonZeroU32, TryReadError<usize, NonZeroU32>> =
971*c3739801SMiguel Ojeda     ///     maybe_u32.map_err(|err| {
972*c3739801SMiguel Ojeda     ///         err.map_src(|src| src.len())
973*c3739801SMiguel Ojeda     ///     });
974*c3739801SMiguel Ojeda     /// ```
975*c3739801SMiguel Ojeda     #[inline]
976*c3739801SMiguel Ojeda     pub fn map_src<NewSrc>(self, f: impl FnOnce(Src) -> NewSrc) -> TryReadError<NewSrc, Dst> {
977*c3739801SMiguel Ojeda         match self {
978*c3739801SMiguel Ojeda             Self::Alignment(i) => match i {},
979*c3739801SMiguel Ojeda             Self::Size(e) => TryReadError::Size(e.map_src(f)),
980*c3739801SMiguel Ojeda             Self::Validity(e) => TryReadError::Validity(e.map_src(f)),
981*c3739801SMiguel Ojeda         }
982*c3739801SMiguel Ojeda     }
983*c3739801SMiguel Ojeda }
984*c3739801SMiguel Ojeda 
985*c3739801SMiguel Ojeda /// The error type of well-aligned, fallible casts.
986*c3739801SMiguel Ojeda ///
987*c3739801SMiguel Ojeda /// This is like [`TryCastError`], but for casts that are always well-aligned.
988*c3739801SMiguel Ojeda /// It is identical to `TryCastError`, except that its alignment error is
989*c3739801SMiguel Ojeda /// [`Infallible`].
990*c3739801SMiguel Ojeda ///
991*c3739801SMiguel Ojeda /// As of this writing, none of zerocopy's API produces this error directly.
992*c3739801SMiguel Ojeda /// However, it is useful since it permits users to infallibly discard alignment
993*c3739801SMiguel Ojeda /// errors when they can prove statically that alignment errors are impossible.
994*c3739801SMiguel Ojeda ///
995*c3739801SMiguel Ojeda /// # Examples
996*c3739801SMiguel Ojeda ///
997*c3739801SMiguel Ojeda /// ```
998*c3739801SMiguel Ojeda /// use core::convert::Infallible;
999*c3739801SMiguel Ojeda /// use zerocopy::*;
1000*c3739801SMiguel Ojeda /// # use zerocopy_derive::*;
1001*c3739801SMiguel Ojeda ///
1002*c3739801SMiguel Ojeda /// #[derive(TryFromBytes, KnownLayout, Unaligned, Immutable)]
1003*c3739801SMiguel Ojeda /// #[repr(C, packed)]
1004*c3739801SMiguel Ojeda /// struct Bools {
1005*c3739801SMiguel Ojeda ///     one: bool,
1006*c3739801SMiguel Ojeda ///     two: bool,
1007*c3739801SMiguel Ojeda ///     many: [bool],
1008*c3739801SMiguel Ojeda /// }
1009*c3739801SMiguel Ojeda ///
1010*c3739801SMiguel Ojeda /// impl Bools {
1011*c3739801SMiguel Ojeda ///     fn parse(bytes: &[u8]) -> Result<&Bools, AlignedTryCastError<&[u8], Bools>> {
1012*c3739801SMiguel Ojeda ///         // Since `Bools: Unaligned`, we can infallibly discard
1013*c3739801SMiguel Ojeda ///         // the alignment error.
1014*c3739801SMiguel Ojeda ///         Bools::try_ref_from_bytes(bytes).map_err(Into::into)
1015*c3739801SMiguel Ojeda ///     }
1016*c3739801SMiguel Ojeda /// }
1017*c3739801SMiguel Ojeda /// ```
1018*c3739801SMiguel Ojeda #[allow(type_alias_bounds)]
1019*c3739801SMiguel Ojeda pub type AlignedTryCastError<Src, Dst: ?Sized + TryFromBytes> =
1020*c3739801SMiguel Ojeda     ConvertError<Infallible, SizeError<Src, Dst>, ValidityError<Src, Dst>>;
1021*c3739801SMiguel Ojeda 
1022*c3739801SMiguel Ojeda /// The error type of a failed allocation.
1023*c3739801SMiguel Ojeda ///
1024*c3739801SMiguel Ojeda /// This type is intended to be deprecated in favor of the standard library's
1025*c3739801SMiguel Ojeda /// [`AllocError`] type once it is stabilized. When that happens, this type will
1026*c3739801SMiguel Ojeda /// be replaced by a type alias to the standard library type. We do not intend
1027*c3739801SMiguel Ojeda /// to treat this as a breaking change; users who wish to avoid breakage should
1028*c3739801SMiguel Ojeda /// avoid writing code which assumes that this is *not* such an alias. For
1029*c3739801SMiguel Ojeda /// example, implementing the same trait for both types will result in an impl
1030*c3739801SMiguel Ojeda /// conflict once this type is an alias.
1031*c3739801SMiguel Ojeda ///
1032*c3739801SMiguel Ojeda /// [`AllocError`]: https://doc.rust-lang.org/alloc/alloc/struct.AllocError.html
1033*c3739801SMiguel Ojeda #[derive(Copy, Clone, PartialEq, Eq, Debug)]
1034*c3739801SMiguel Ojeda pub struct AllocError;
1035*c3739801SMiguel Ojeda 
1036*c3739801SMiguel Ojeda #[cfg(test)]
1037*c3739801SMiguel Ojeda mod tests {
1038*c3739801SMiguel Ojeda     use core::convert::Infallible;
1039*c3739801SMiguel Ojeda 
1040*c3739801SMiguel Ojeda     use super::*;
1041*c3739801SMiguel Ojeda 
1042*c3739801SMiguel Ojeda     #[test]
1043*c3739801SMiguel Ojeda     fn test_send_sync() {
1044*c3739801SMiguel Ojeda         // Test that all error types are `Send + Sync` even if `Dst: !Send +
1045*c3739801SMiguel Ojeda         // !Sync`.
1046*c3739801SMiguel Ojeda 
1047*c3739801SMiguel Ojeda         #[allow(dead_code)]
1048*c3739801SMiguel Ojeda         fn is_send_sync<T: Send + Sync>(_t: T) {}
1049*c3739801SMiguel Ojeda 
1050*c3739801SMiguel Ojeda         #[allow(dead_code)]
1051*c3739801SMiguel Ojeda         fn alignment_err_is_send_sync<Src: Send + Sync, Dst>(err: AlignmentError<Src, Dst>) {
1052*c3739801SMiguel Ojeda             is_send_sync(err)
1053*c3739801SMiguel Ojeda         }
1054*c3739801SMiguel Ojeda 
1055*c3739801SMiguel Ojeda         #[allow(dead_code)]
1056*c3739801SMiguel Ojeda         fn size_err_is_send_sync<Src: Send + Sync, Dst>(err: SizeError<Src, Dst>) {
1057*c3739801SMiguel Ojeda             is_send_sync(err)
1058*c3739801SMiguel Ojeda         }
1059*c3739801SMiguel Ojeda 
1060*c3739801SMiguel Ojeda         #[allow(dead_code)]
1061*c3739801SMiguel Ojeda         fn validity_err_is_send_sync<Src: Send + Sync, Dst: TryFromBytes>(
1062*c3739801SMiguel Ojeda             err: ValidityError<Src, Dst>,
1063*c3739801SMiguel Ojeda         ) {
1064*c3739801SMiguel Ojeda             is_send_sync(err)
1065*c3739801SMiguel Ojeda         }
1066*c3739801SMiguel Ojeda 
1067*c3739801SMiguel Ojeda         #[allow(dead_code)]
1068*c3739801SMiguel Ojeda         fn convert_error_is_send_sync<Src: Send + Sync, Dst: TryFromBytes>(
1069*c3739801SMiguel Ojeda             err: ConvertError<
1070*c3739801SMiguel Ojeda                 AlignmentError<Src, Dst>,
1071*c3739801SMiguel Ojeda                 SizeError<Src, Dst>,
1072*c3739801SMiguel Ojeda                 ValidityError<Src, Dst>,
1073*c3739801SMiguel Ojeda             >,
1074*c3739801SMiguel Ojeda         ) {
1075*c3739801SMiguel Ojeda             is_send_sync(err)
1076*c3739801SMiguel Ojeda         }
1077*c3739801SMiguel Ojeda     }
1078*c3739801SMiguel Ojeda 
1079*c3739801SMiguel Ojeda     #[test]
1080*c3739801SMiguel Ojeda     fn test_eq_partial_eq_clone() {
1081*c3739801SMiguel Ojeda         // Test that all error types implement `Eq`, `PartialEq`
1082*c3739801SMiguel Ojeda         // and `Clone` if src does
1083*c3739801SMiguel Ojeda         // even if `Dst: !Eq`, `!PartialEq`, `!Clone`.
1084*c3739801SMiguel Ojeda 
1085*c3739801SMiguel Ojeda         #[allow(dead_code)]
1086*c3739801SMiguel Ojeda         fn is_eq_partial_eq_clone<T: Eq + PartialEq + Clone>(_t: T) {}
1087*c3739801SMiguel Ojeda 
1088*c3739801SMiguel Ojeda         #[allow(dead_code)]
1089*c3739801SMiguel Ojeda         fn alignment_err_is_eq_partial_eq_clone<Src: Eq + PartialEq + Clone, Dst>(
1090*c3739801SMiguel Ojeda             err: AlignmentError<Src, Dst>,
1091*c3739801SMiguel Ojeda         ) {
1092*c3739801SMiguel Ojeda             is_eq_partial_eq_clone(err)
1093*c3739801SMiguel Ojeda         }
1094*c3739801SMiguel Ojeda 
1095*c3739801SMiguel Ojeda         #[allow(dead_code)]
1096*c3739801SMiguel Ojeda         fn size_err_is_eq_partial_eq_clone<Src: Eq + PartialEq + Clone, Dst>(
1097*c3739801SMiguel Ojeda             err: SizeError<Src, Dst>,
1098*c3739801SMiguel Ojeda         ) {
1099*c3739801SMiguel Ojeda             is_eq_partial_eq_clone(err)
1100*c3739801SMiguel Ojeda         }
1101*c3739801SMiguel Ojeda 
1102*c3739801SMiguel Ojeda         #[allow(dead_code)]
1103*c3739801SMiguel Ojeda         fn validity_err_is_eq_partial_eq_clone<Src: Eq + PartialEq + Clone, Dst: TryFromBytes>(
1104*c3739801SMiguel Ojeda             err: ValidityError<Src, Dst>,
1105*c3739801SMiguel Ojeda         ) {
1106*c3739801SMiguel Ojeda             is_eq_partial_eq_clone(err)
1107*c3739801SMiguel Ojeda         }
1108*c3739801SMiguel Ojeda 
1109*c3739801SMiguel Ojeda         #[allow(dead_code)]
1110*c3739801SMiguel Ojeda         fn convert_error_is_eq_partial_eq_clone<Src: Eq + PartialEq + Clone, Dst: TryFromBytes>(
1111*c3739801SMiguel Ojeda             err: ConvertError<
1112*c3739801SMiguel Ojeda                 AlignmentError<Src, Dst>,
1113*c3739801SMiguel Ojeda                 SizeError<Src, Dst>,
1114*c3739801SMiguel Ojeda                 ValidityError<Src, Dst>,
1115*c3739801SMiguel Ojeda             >,
1116*c3739801SMiguel Ojeda         ) {
1117*c3739801SMiguel Ojeda             is_eq_partial_eq_clone(err)
1118*c3739801SMiguel Ojeda         }
1119*c3739801SMiguel Ojeda     }
1120*c3739801SMiguel Ojeda 
1121*c3739801SMiguel Ojeda     #[test]
1122*c3739801SMiguel Ojeda     fn alignment_display() {
1123*c3739801SMiguel Ojeda         #[repr(C, align(128))]
1124*c3739801SMiguel Ojeda         struct Aligned {
1125*c3739801SMiguel Ojeda             bytes: [u8; 128],
1126*c3739801SMiguel Ojeda         }
1127*c3739801SMiguel Ojeda 
1128*c3739801SMiguel Ojeda         impl_known_layout!(elain::Align::<8>);
1129*c3739801SMiguel Ojeda 
1130*c3739801SMiguel Ojeda         let aligned = Aligned { bytes: [0; 128] };
1131*c3739801SMiguel Ojeda 
1132*c3739801SMiguel Ojeda         let bytes = &aligned.bytes[1..];
1133*c3739801SMiguel Ojeda         let addr = crate::util::AsAddress::addr(bytes);
1134*c3739801SMiguel Ojeda         assert_eq!(
1135*c3739801SMiguel Ojeda             AlignmentError::<_, elain::Align::<8>>::new_checked(bytes).to_string(),
1136*c3739801SMiguel Ojeda             format!("The conversion failed because the address of the source is not a multiple of the alignment of the destination type.\n\
1137*c3739801SMiguel Ojeda             \nSource type: &[u8]\
1138*c3739801SMiguel Ojeda             \nSource address: 0x{:x} (a multiple of 1)\
1139*c3739801SMiguel Ojeda             \nDestination type: elain::Align<8>\
1140*c3739801SMiguel Ojeda             \nDestination alignment: 8", addr)
1141*c3739801SMiguel Ojeda         );
1142*c3739801SMiguel Ojeda 
1143*c3739801SMiguel Ojeda         let bytes = &aligned.bytes[2..];
1144*c3739801SMiguel Ojeda         let addr = crate::util::AsAddress::addr(bytes);
1145*c3739801SMiguel Ojeda         assert_eq!(
1146*c3739801SMiguel Ojeda             AlignmentError::<_, elain::Align::<8>>::new_checked(bytes).to_string(),
1147*c3739801SMiguel Ojeda             format!("The conversion failed because the address of the source is not a multiple of the alignment of the destination type.\n\
1148*c3739801SMiguel Ojeda             \nSource type: &[u8]\
1149*c3739801SMiguel Ojeda             \nSource address: 0x{:x} (a multiple of 2)\
1150*c3739801SMiguel Ojeda             \nDestination type: elain::Align<8>\
1151*c3739801SMiguel Ojeda             \nDestination alignment: 8", addr)
1152*c3739801SMiguel Ojeda         );
1153*c3739801SMiguel Ojeda 
1154*c3739801SMiguel Ojeda         let bytes = &aligned.bytes[3..];
1155*c3739801SMiguel Ojeda         let addr = crate::util::AsAddress::addr(bytes);
1156*c3739801SMiguel Ojeda         assert_eq!(
1157*c3739801SMiguel Ojeda             AlignmentError::<_, elain::Align::<8>>::new_checked(bytes).to_string(),
1158*c3739801SMiguel Ojeda             format!("The conversion failed because the address of the source is not a multiple of the alignment of the destination type.\n\
1159*c3739801SMiguel Ojeda             \nSource type: &[u8]\
1160*c3739801SMiguel Ojeda             \nSource address: 0x{:x} (a multiple of 1)\
1161*c3739801SMiguel Ojeda             \nDestination type: elain::Align<8>\
1162*c3739801SMiguel Ojeda             \nDestination alignment: 8", addr)
1163*c3739801SMiguel Ojeda         );
1164*c3739801SMiguel Ojeda 
1165*c3739801SMiguel Ojeda         let bytes = &aligned.bytes[4..];
1166*c3739801SMiguel Ojeda         let addr = crate::util::AsAddress::addr(bytes);
1167*c3739801SMiguel Ojeda         assert_eq!(
1168*c3739801SMiguel Ojeda             AlignmentError::<_, elain::Align::<8>>::new_checked(bytes).to_string(),
1169*c3739801SMiguel Ojeda             format!("The conversion failed because the address of the source is not a multiple of the alignment of the destination type.\n\
1170*c3739801SMiguel Ojeda             \nSource type: &[u8]\
1171*c3739801SMiguel Ojeda             \nSource address: 0x{:x} (a multiple of 4)\
1172*c3739801SMiguel Ojeda             \nDestination type: elain::Align<8>\
1173*c3739801SMiguel Ojeda             \nDestination alignment: 8", addr)
1174*c3739801SMiguel Ojeda         );
1175*c3739801SMiguel Ojeda     }
1176*c3739801SMiguel Ojeda 
1177*c3739801SMiguel Ojeda     #[test]
1178*c3739801SMiguel Ojeda     fn size_display() {
1179*c3739801SMiguel Ojeda         assert_eq!(
1180*c3739801SMiguel Ojeda             SizeError::<_, [u8]>::new(&[0u8; 2][..]).to_string(),
1181*c3739801SMiguel Ojeda             "The conversion failed because the source was incorrectly sized to complete the conversion into the destination type.\n\
1182*c3739801SMiguel Ojeda             \nSource type: &[u8]\
1183*c3739801SMiguel Ojeda             \nSource size: 2 bytes\
1184*c3739801SMiguel Ojeda             \nDestination type: [u8]"
1185*c3739801SMiguel Ojeda         );
1186*c3739801SMiguel Ojeda 
1187*c3739801SMiguel Ojeda         assert_eq!(
1188*c3739801SMiguel Ojeda             SizeError::<_, [u8; 2]>::new(&[0u8; 1][..]).to_string(),
1189*c3739801SMiguel Ojeda             "The conversion failed because the source was incorrectly sized to complete the conversion into the destination type.\n\
1190*c3739801SMiguel Ojeda             \nSource type: &[u8]\
1191*c3739801SMiguel Ojeda             \nSource size: 1 byte\
1192*c3739801SMiguel Ojeda             \nDestination size: 2 bytes\
1193*c3739801SMiguel Ojeda             \nDestination type: [u8; 2]"
1194*c3739801SMiguel Ojeda         );
1195*c3739801SMiguel Ojeda     }
1196*c3739801SMiguel Ojeda 
1197*c3739801SMiguel Ojeda     #[test]
1198*c3739801SMiguel Ojeda     fn validity_display() {
1199*c3739801SMiguel Ojeda         assert_eq!(
1200*c3739801SMiguel Ojeda             ValidityError::<_, bool>::new(&[2u8; 1][..]).to_string(),
1201*c3739801SMiguel Ojeda             "The conversion failed because the source bytes are not a valid value of the destination type.\n\
1202*c3739801SMiguel Ojeda             \n\
1203*c3739801SMiguel Ojeda             Destination type: bool"
1204*c3739801SMiguel Ojeda         );
1205*c3739801SMiguel Ojeda     }
1206*c3739801SMiguel Ojeda 
1207*c3739801SMiguel Ojeda     #[test]
1208*c3739801SMiguel Ojeda     fn test_convert_error_debug() {
1209*c3739801SMiguel Ojeda         let err: ConvertError<
1210*c3739801SMiguel Ojeda             AlignmentError<&[u8], u16>,
1211*c3739801SMiguel Ojeda             SizeError<&[u8], u16>,
1212*c3739801SMiguel Ojeda             ValidityError<&[u8], bool>,
1213*c3739801SMiguel Ojeda         > = ConvertError::Alignment(AlignmentError::new_checked(&[0u8]));
1214*c3739801SMiguel Ojeda         assert_eq!(format!("{:?}", err), "Alignment(AlignmentError)");
1215*c3739801SMiguel Ojeda 
1216*c3739801SMiguel Ojeda         let err: ConvertError<
1217*c3739801SMiguel Ojeda             AlignmentError<&[u8], u16>,
1218*c3739801SMiguel Ojeda             SizeError<&[u8], u16>,
1219*c3739801SMiguel Ojeda             ValidityError<&[u8], bool>,
1220*c3739801SMiguel Ojeda         > = ConvertError::Size(SizeError::new(&[0u8]));
1221*c3739801SMiguel Ojeda         assert_eq!(format!("{:?}", err), "Size(SizeError)");
1222*c3739801SMiguel Ojeda 
1223*c3739801SMiguel Ojeda         let err: ConvertError<
1224*c3739801SMiguel Ojeda             AlignmentError<&[u8], u16>,
1225*c3739801SMiguel Ojeda             SizeError<&[u8], u16>,
1226*c3739801SMiguel Ojeda             ValidityError<&[u8], bool>,
1227*c3739801SMiguel Ojeda         > = ConvertError::Validity(ValidityError::new(&[0u8]));
1228*c3739801SMiguel Ojeda         assert_eq!(format!("{:?}", err), "Validity(ValidityError)");
1229*c3739801SMiguel Ojeda     }
1230*c3739801SMiguel Ojeda 
1231*c3739801SMiguel Ojeda     #[test]
1232*c3739801SMiguel Ojeda     fn test_convert_error_from_unaligned() {
1233*c3739801SMiguel Ojeda         // u8 is Unaligned
1234*c3739801SMiguel Ojeda         let err: ConvertError<
1235*c3739801SMiguel Ojeda             AlignmentError<&[u8], u8>,
1236*c3739801SMiguel Ojeda             SizeError<&[u8], u8>,
1237*c3739801SMiguel Ojeda             ValidityError<&[u8], bool>,
1238*c3739801SMiguel Ojeda         > = ConvertError::Size(SizeError::new(&[0u8]));
1239*c3739801SMiguel Ojeda         let converted: ConvertError<Infallible, SizeError<&[u8], u8>, ValidityError<&[u8], bool>> =
1240*c3739801SMiguel Ojeda             ConvertError::from(err);
1241*c3739801SMiguel Ojeda         match converted {
1242*c3739801SMiguel Ojeda             ConvertError::Size(_) => {}
1243*c3739801SMiguel Ojeda             _ => panic!("Expected Size error"),
1244*c3739801SMiguel Ojeda         }
1245*c3739801SMiguel Ojeda     }
1246*c3739801SMiguel Ojeda 
1247*c3739801SMiguel Ojeda     #[test]
1248*c3739801SMiguel Ojeda     fn test_alignment_error_display_debug() {
1249*c3739801SMiguel Ojeda         let err: AlignmentError<&[u8], u16> = AlignmentError::new_checked(&[0u8]);
1250*c3739801SMiguel Ojeda         assert!(format!("{:?}", err).contains("AlignmentError"));
1251*c3739801SMiguel Ojeda         assert!(format!("{}", err).contains("address of the source is not a multiple"));
1252*c3739801SMiguel Ojeda     }
1253*c3739801SMiguel Ojeda 
1254*c3739801SMiguel Ojeda     #[test]
1255*c3739801SMiguel Ojeda     fn test_size_error_display_debug() {
1256*c3739801SMiguel Ojeda         let err: SizeError<&[u8], u16> = SizeError::new(&[0u8]);
1257*c3739801SMiguel Ojeda         assert!(format!("{:?}", err).contains("SizeError"));
1258*c3739801SMiguel Ojeda         assert!(format!("{}", err).contains("source was incorrectly sized"));
1259*c3739801SMiguel Ojeda     }
1260*c3739801SMiguel Ojeda 
1261*c3739801SMiguel Ojeda     #[test]
1262*c3739801SMiguel Ojeda     fn test_validity_error_display_debug() {
1263*c3739801SMiguel Ojeda         let err: ValidityError<&[u8], bool> = ValidityError::new(&[0u8]);
1264*c3739801SMiguel Ojeda         assert!(format!("{:?}", err).contains("ValidityError"));
1265*c3739801SMiguel Ojeda         assert!(format!("{}", err).contains("source bytes are not a valid value"));
1266*c3739801SMiguel Ojeda     }
1267*c3739801SMiguel Ojeda 
1268*c3739801SMiguel Ojeda     #[test]
1269*c3739801SMiguel Ojeda     fn test_convert_error_display_debug_more() {
1270*c3739801SMiguel Ojeda         let err: ConvertError<
1271*c3739801SMiguel Ojeda             AlignmentError<&[u8], u16>,
1272*c3739801SMiguel Ojeda             SizeError<&[u8], u16>,
1273*c3739801SMiguel Ojeda             ValidityError<&[u8], bool>,
1274*c3739801SMiguel Ojeda         > = ConvertError::Alignment(AlignmentError::new_checked(&[0u8]));
1275*c3739801SMiguel Ojeda         assert!(format!("{}", err).contains("address of the source is not a multiple"));
1276*c3739801SMiguel Ojeda 
1277*c3739801SMiguel Ojeda         let err: ConvertError<
1278*c3739801SMiguel Ojeda             AlignmentError<&[u8], u16>,
1279*c3739801SMiguel Ojeda             SizeError<&[u8], u16>,
1280*c3739801SMiguel Ojeda             ValidityError<&[u8], bool>,
1281*c3739801SMiguel Ojeda         > = ConvertError::Size(SizeError::new(&[0u8]));
1282*c3739801SMiguel Ojeda         assert!(format!("{}", err).contains("source was incorrectly sized"));
1283*c3739801SMiguel Ojeda 
1284*c3739801SMiguel Ojeda         let err: ConvertError<
1285*c3739801SMiguel Ojeda             AlignmentError<&[u8], u16>,
1286*c3739801SMiguel Ojeda             SizeError<&[u8], u16>,
1287*c3739801SMiguel Ojeda             ValidityError<&[u8], bool>,
1288*c3739801SMiguel Ojeda         > = ConvertError::Validity(ValidityError::new(&[0u8]));
1289*c3739801SMiguel Ojeda         assert!(format!("{}", err).contains("source bytes are not a valid value"));
1290*c3739801SMiguel Ojeda     }
1291*c3739801SMiguel Ojeda 
1292*c3739801SMiguel Ojeda     #[test]
1293*c3739801SMiguel Ojeda     fn test_alignment_error_methods() {
1294*c3739801SMiguel Ojeda         let err: AlignmentError<&[u8], u16> = AlignmentError::new_checked(&[0u8]);
1295*c3739801SMiguel Ojeda 
1296*c3739801SMiguel Ojeda         // into_src
1297*c3739801SMiguel Ojeda         let src = err.clone().into_src();
1298*c3739801SMiguel Ojeda         assert_eq!(src, &[0u8]);
1299*c3739801SMiguel Ojeda 
1300*c3739801SMiguel Ojeda         // into
1301*c3739801SMiguel Ojeda         let converted: ConvertError<
1302*c3739801SMiguel Ojeda             AlignmentError<&[u8], u16>,
1303*c3739801SMiguel Ojeda             SizeError<&[u8], u16>,
1304*c3739801SMiguel Ojeda             ValidityError<&[u8], bool>,
1305*c3739801SMiguel Ojeda         > = err.clone().into();
1306*c3739801SMiguel Ojeda         match converted {
1307*c3739801SMiguel Ojeda             ConvertError::Alignment(_) => {}
1308*c3739801SMiguel Ojeda             _ => panic!("Expected Alignment error"),
1309*c3739801SMiguel Ojeda         }
1310*c3739801SMiguel Ojeda 
1311*c3739801SMiguel Ojeda         // clone
1312*c3739801SMiguel Ojeda         let cloned = err.clone();
1313*c3739801SMiguel Ojeda         assert_eq!(err, cloned);
1314*c3739801SMiguel Ojeda 
1315*c3739801SMiguel Ojeda         // eq
1316*c3739801SMiguel Ojeda         assert_eq!(err, cloned);
1317*c3739801SMiguel Ojeda         let err2: AlignmentError<&[u8], u16> = AlignmentError::new_checked(&[1u8]);
1318*c3739801SMiguel Ojeda         assert_ne!(err, err2);
1319*c3739801SMiguel Ojeda     }
1320*c3739801SMiguel Ojeda 
1321*c3739801SMiguel Ojeda     #[test]
1322*c3739801SMiguel Ojeda     fn test_convert_error_from_unaligned_variants() {
1323*c3739801SMiguel Ojeda         // u8 is Unaligned
1324*c3739801SMiguel Ojeda         let err: ConvertError<
1325*c3739801SMiguel Ojeda             AlignmentError<&[u8], u8>,
1326*c3739801SMiguel Ojeda             SizeError<&[u8], u8>,
1327*c3739801SMiguel Ojeda             ValidityError<&[u8], bool>,
1328*c3739801SMiguel Ojeda         > = ConvertError::Validity(ValidityError::new(&[0u8]));
1329*c3739801SMiguel Ojeda         let converted: ConvertError<Infallible, SizeError<&[u8], u8>, ValidityError<&[u8], bool>> =
1330*c3739801SMiguel Ojeda             ConvertError::from(err);
1331*c3739801SMiguel Ojeda         match converted {
1332*c3739801SMiguel Ojeda             ConvertError::Validity(_) => {}
1333*c3739801SMiguel Ojeda             _ => panic!("Expected Validity error"),
1334*c3739801SMiguel Ojeda         }
1335*c3739801SMiguel Ojeda 
1336*c3739801SMiguel Ojeda         let err: ConvertError<
1337*c3739801SMiguel Ojeda             AlignmentError<&[u8], u8>,
1338*c3739801SMiguel Ojeda             SizeError<&[u8], u8>,
1339*c3739801SMiguel Ojeda             ValidityError<&[u8], bool>,
1340*c3739801SMiguel Ojeda         > = ConvertError::Size(SizeError::new(&[0u8]));
1341*c3739801SMiguel Ojeda         let converted: ConvertError<Infallible, SizeError<&[u8], u8>, ValidityError<&[u8], bool>> =
1342*c3739801SMiguel Ojeda             ConvertError::from(err);
1343*c3739801SMiguel Ojeda         match converted {
1344*c3739801SMiguel Ojeda             ConvertError::Size(_) => {}
1345*c3739801SMiguel Ojeda             _ => panic!("Expected Size error"),
1346*c3739801SMiguel Ojeda         }
1347*c3739801SMiguel Ojeda     }
1348*c3739801SMiguel Ojeda }
1349