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