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