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