//! Types related to error reporting. //! //! ## Single failure mode errors //! //! Generally speaking, zerocopy's conversions may fail for one of up to three //! reasons: //! - [`AlignmentError`]: the conversion source was improperly aligned //! - [`SizeError`]: the conversion source was of incorrect size //! - [`ValidityError`]: the conversion source contained invalid data //! //! Methods that only have one failure mode, like //! [`FromBytes::read_from_bytes`], return that mode's corresponding error type //! directly. //! //! ## Compound errors //! //! Conversion methods that have either two or three possible failure modes //! return one of these error types: //! - [`CastError`]: the error type of reference conversions //! - [`TryCastError`]: the error type of fallible reference conversions //! - [`TryReadError`]: the error type of fallible read conversions //! //! ## [`Unaligned`] destination types //! //! For [`Unaligned`] destination types, alignment errors are impossible. All //! compound error types support infallibly discarding the alignment error via //! [`From`] so long as `Dst: Unaligned`. For example, see [`<SizeError as //! From<ConvertError>>::from`][size-error-from]. //! //! [size-error-from]: struct.SizeError.html#method.from-1 //! //! ## Accessing the conversion source //! //! All error types provide an `into_src` method that converts the error into //! the source value underlying the failed conversion. //! //! ## Display formatting //! //! All error types provide a `Display` implementation that produces a //! human-readable error message. When `debug_assertions` are enabled, these //! error messages are verbose and may include potentially sensitive //! information, including: //! //! - the names of the involved types //! - the sizes of the involved types //! - the addresses of the involved types //! - the contents of the involved types //! //! When `debug_assertions` are disabled (as is default for `release` builds), //! such potentially sensitive information is excluded. //! //! In the future, we may support manually configuring this behavior. If you are //! interested in this feature, [let us know on GitHub][issue-1457] so we know //! to prioritize it. //! //! [issue-1457]: https://github.com/google/zerocopy/issues/1457 //! //! ## Validation order //! //! Our conversion methods typically check alignment, then size, then bit //! validity. However, we do not guarantee that this is always the case, and //! this behavior may change between releases. //! //! ## `Send`, `Sync`, and `'static` //! //! Our error types are `Send`, `Sync`, and `'static` when their `Src` parameter //! is `Send`, `Sync`, or `'static`, respectively. This can cause issues when an //! error is sent or synchronized across threads; e.g.: //! //! ```compile_fail,E0515 //! use zerocopy::*; //! //! let result: SizeError<&[u8], u32> = std::thread::spawn(|| { //! let source = &mut [0u8, 1, 2][..]; //! // Try (and fail) to read a `u32` from `source`. //! u32::read_from_bytes(source).unwrap_err() //! }).join().unwrap(); //! ``` //! //! To work around this, use [`map_src`][CastError::map_src] to convert the //! source parameter to an unproblematic type; e.g.: //! //! ``` //! use zerocopy::*; //! //! let result: SizeError<(), u32> = std::thread::spawn(|| { //! let source = &mut [0u8, 1, 2][..]; //! // Try (and fail) to read a `u32` from `source`. //! u32::read_from_bytes(source).unwrap_err() //! // Erase the error source. //! .map_src(drop) //! }).join().unwrap(); //! ``` //! //! Alternatively, use `.to_string()` to eagerly convert the error into a //! human-readable message; e.g.: //! //! ``` //! use zerocopy::*; //! //! let result: Result<u32, String> = std::thread::spawn(|| { //! let source = &mut [0u8, 1, 2][..]; //! // Try (and fail) to read a `u32` from `source`. //! u32::read_from_bytes(source) //! // Eagerly render the error message. //! .map_err(|err| err.to_string()) //! }).join().unwrap(); //! ``` #[cfg(zerocopy_core_error_1_81_0)] use core::error::Error; use core::{
convert::Infallible,
fmt::{self, Debug, Write},
ops::Deref,
}; #[cfg(all(not(zerocopy_core_error_1_81_0), any(feature = "std", test)))] use std::error::Error;
/// Zerocopy's generic error type. /// /// Generally speaking, zerocopy's conversions may fail for one of up to three /// reasons: /// - [`AlignmentError`]: the conversion source was improperly aligned /// - [`SizeError`]: the conversion source was of incorrect size /// - [`ValidityError`]: the conversion source contained invalid data /// /// However, not all conversions produce all errors. For instance, /// [`FromBytes::ref_from_bytes`] may fail due to alignment or size issues, but /// not validity issues. This generic error type captures these /// (im)possibilities via parameterization: `A` is parameterized with /// [`AlignmentError`], `S` is parameterized with [`SizeError`], and `V` is /// parameterized with [`Infallible`]. /// /// Zerocopy never uses this type directly in its API. Rather, we provide three /// pre-parameterized aliases: /// - [`CastError`]: the error type of reference conversions /// - [`TryCastError`]: the error type of fallible reference conversions /// - [`TryReadError`]: the error type of fallible read conversions #[derive(PartialEq, Eq)] pubenum ConvertError<A, S, V> { /// The conversion source was improperly aligned.
Alignment(A), /// The conversion source was of incorrect size.
Size(S), /// The conversion source contained invalid data.
Validity(V),
}
impl<Src, Dst: ?Sized + Unaligned, S, V> From<ConvertError<AlignmentError<Src, Dst>, S, V>> for ConvertError<Infallible, S, V>
{ /// Infallibly discards the alignment error from this `ConvertError` since /// `Dst` is unaligned. /// /// Since [`Dst: Unaligned`], it is impossible to encounter an alignment /// error. This method permits discarding that alignment error infallibly /// and replacing it with [`Infallible`]. /// /// [`Dst: Unaligned`]: crate::Unaligned /// /// # Examples /// /// ``` /// use core::convert::Infallible; /// use zerocopy::*; /// # use zerocopy_derive::*; /// /// #[derive(TryFromBytes, KnownLayout, Unaligned, Immutable)] /// #[repr(C, packed)] /// struct Bools { /// one: bool, /// two: bool, /// many: [bool], /// } /// /// impl Bools { /// fn parse(bytes: &[u8]) -> Result<&Bools, AlignedTryCastError<&[u8], Bools>> { /// // Since `Bools: Unaligned`, we can infallibly discard /// // the alignment error. /// Bools::try_ref_from_bytes(bytes).map_err(Into::into) /// } /// } /// ``` #[inline] fn from(err: ConvertError<AlignmentError<Src, Dst>, S, V>) -> ConvertError<Infallible, S, V> { match err {
ConvertError::Alignment(e) => ConvertError::Alignment(Infallible::from(e)),
ConvertError::Size(e) => ConvertError::Size(e),
ConvertError::Validity(e) => ConvertError::Validity(e),
}
}
}
/// The error emitted if the conversion source is improperly aligned. #[derive(PartialEq, Eq)] pubstruct AlignmentError<Src, Dst: ?Sized> { /// The source value involved in the conversion.
src: Src, /// The inner destination type inolved in the conversion. /// /// INVARIANT: An `AlignmentError` may only be constructed if `Dst`'s /// alignment requirement is greater than one.
dst: SendSyncPhantomData<Dst>,
}
impl<Src, Dst: ?Sized> AlignmentError<Src, Dst> { /// # Safety /// /// The caller must ensure that `Dst`'s alignment requirement is greater /// than one. pub(crate) unsafefn new_unchecked(src: Src) -> Self { // INVARIANT: The caller guarantees that `Dst`'s alignment requirement // is greater than one. Self { src, dst: SendSyncPhantomData::default() }
}
/// Produces the source underlying the failed conversion. #[inline] pubfn into_src(self) -> Src { self.src
}
pub(crate) fn with_src<NewSrc>(self, new_src: NewSrc) -> AlignmentError<NewSrc, Dst> { // INVARIANT: `with_src` doesn't change the type of `Dst`, so the // invariant that `Dst`'s alignment requirement is greater than one is // preserved.
AlignmentError { src: new_src, dst: SendSyncPhantomData::default() }
}
/// Maps the source value associated with the conversion error. /// /// This can help mitigate [issues with `Send`, `Sync` and `'static` /// bounds][self#send-sync-and-static]. /// /// # Examples /// /// ``` /// use zerocopy::*; /// /// let unaligned = Unalign::new(0u16); /// /// // Attempt to deref `unaligned`. This might fail with an alignment error. /// let maybe_n: Result<&u16, AlignmentError<&Unalign<u16>, u16>> = unaligned.try_deref(); /// /// // Map the error's source to its address as a usize. /// let maybe_n: Result<&u16, AlignmentError<usize, u16>> = maybe_n.map_err(|err| { /// err.map_src(|src| src as *const _ as usize) /// }); /// ``` #[inline] pubfn map_src<NewSrc>(self, f: impl FnOnce(Src) -> NewSrc) -> AlignmentError<NewSrc, Dst> {
AlignmentError { src: f(self.src), dst: SendSyncPhantomData::default() }
}
/// Format extra details for a verbose, human-readable error message. /// /// This formatting may include potentially sensitive information. fn display_verbose_extras(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result where
Src: Deref,
Dst: KnownLayout,
{ #[allow(clippy::as_conversions)] let addr = self.src.deref() as *const _ as *const (); let addr_align = 2usize.pow((crate::util::AsAddress::addr(addr)).trailing_zeros());
f.write_str("\nDestination alignment: ")?;
<Dst as KnownLayout>::LAYOUT.align.get().fmt(f)?;
Ok(())
}
}
impl<Src, Dst: ?Sized + Unaligned> From<AlignmentError<Src, Dst>> for Infallible { #[inline(always)] fn from(_: AlignmentError<Src, Dst>) -> Infallible { // SAFETY: `AlignmentError`s can only be constructed when `Dst`'s // alignment requirement is greater than one. In this block, `Dst: // Unaligned`, which means that its alignment requirement is equal to // one. Thus, it's not possible to reach here at runtime. unsafe { core::hint::unreachable_unchecked() }
}
}
#[cfg(test)] impl<Src, Dst> AlignmentError<Src, Dst> { // A convenience constructor so that test code doesn't need to write // `unsafe`. fn new_checked(src: Src) -> AlignmentError<Src, Dst> {
assert_ne!(core::mem::align_of::<Dst>(), 1); // SAFETY: The preceding assertion guarantees that `Dst`'s alignment // requirement is greater than one. unsafe { AlignmentError::new_unchecked(src) }
}
}
/// Produces a human-readable error message. /// /// The message differs between debug and release builds. When /// `debug_assertions` are enabled, this message is verbose and includes /// potentially sensitive information. impl<Src, Dst: ?Sized> fmt::Display for AlignmentError<Src, Dst> where
Src: Deref,
Dst: KnownLayout,
{ #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("The conversion failed because the address of the source is not a multiple of the alignment of the destination type.")?;
/// The error emitted if the conversion source is of incorrect size. #[derive(PartialEq, Eq)] pubstruct SizeError<Src, Dst: ?Sized> { /// The source value involved in the conversion.
src: Src, /// The inner destination type inolved in the conversion.
dst: SendSyncPhantomData<Dst>,
}
/// Produces the source underlying the failed conversion. #[inline] pubfn into_src(self) -> Src { self.src
}
/// Sets the source value associated with the conversion error. pub(crate) fn with_src<NewSrc>(self, new_src: NewSrc) -> SizeError<NewSrc, Dst> {
SizeError { src: new_src, dst: SendSyncPhantomData::default() }
}
/// Maps the source value associated with the conversion error. /// /// This can help mitigate [issues with `Send`, `Sync` and `'static` /// bounds][self#send-sync-and-static]. /// /// # Examples /// /// ``` /// use zerocopy::*; /// /// let source: [u8; 3] = [0, 1, 2]; /// /// // Try to read a `u32` from `source`. This will fail because there are insufficient /// // bytes in `source`. /// let maybe_u32: Result<u32, SizeError<&[u8], u32>> = u32::read_from_bytes(&source[..]); /// /// // Map the error's source to its size. /// let maybe_u32: Result<u32, SizeError<usize, u32>> = maybe_u32.map_err(|err| { /// err.map_src(|src| src.len()) /// }); /// ``` #[inline] pubfn map_src<NewSrc>(self, f: impl FnOnce(Src) -> NewSrc) -> SizeError<NewSrc, Dst> {
SizeError { src: f(self.src), dst: SendSyncPhantomData::default() }
}
/// Sets the destination type associated with the conversion error. pub(crate) fn with_dst<NewDst: ?Sized>(self) -> SizeError<Src, NewDst> {
SizeError { src: self.src, dst: SendSyncPhantomData::default() }
}
/// Converts the error into a general [`ConvertError`]. pub(crate) fn into<A, V>(self) -> ConvertError<A, Self, V> {
ConvertError::Size(self)
}
/// Format extra details for a verbose, human-readable error message. /// /// This formatting may include potentially sensitive information. fn display_verbose_extras(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result where
Src: Deref,
Dst: KnownLayout,
{ // include the source type
f.write_str("\nSource type: ")?;
f.write_str(core::any::type_name::<Src>())?;
// include the source.deref() size let src_size = core::mem::size_of_val(&*self.src);
f.write_str("\nSource size: ")?;
src_size.fmt(f)?;
f.write_str(" byte")?; if src_size != 1 {
f.write_char('s')?;
}
// if `Dst` is `Sized`, include the `Dst` size ifletcrate::SizeInfo::Sized { size } = Dst::LAYOUT.size_info {
f.write_str("\nDestination size: ")?;
size.fmt(f)?;
f.write_str(" byte")?; if size != 1 {
f.write_char('s')?;
}
}
// include the destination type
f.write_str("\nDestination type: ")?;
f.write_str(core::any::type_name::<Dst>())?;
/// Produces a human-readable error message. /// /// The message differs between debug and release builds. When /// `debug_assertions` are enabled, this message is verbose and includes /// potentially sensitive information. impl<Src, Dst: ?Sized> fmt::Display for SizeError<Src, Dst> where
Src: Deref,
Dst: KnownLayout,
{ #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("The conversion failed because the source was incorrectly sized to complete the conversion into the destination type.")?; if cfg!(debug_assertions) {
f.write_str("\n")?; self.display_verbose_extras(f)?;
}
Ok(())
}
}
/// The error emitted if the conversion source contains invalid data. #[derive(PartialEq, Eq)] pubstruct ValidityError<Src, Dst: ?Sized + TryFromBytes> { /// The source value involved in the conversion. pub(crate) src: Src, /// The inner destination type inolved in the conversion.
dst: SendSyncPhantomData<Dst>,
}
/// Produces the source underlying the failed conversion. #[inline] pubfn into_src(self) -> Src { self.src
}
/// Maps the source value associated with the conversion error. /// /// This can help mitigate [issues with `Send`, `Sync` and `'static` /// bounds][self#send-sync-and-static]. /// /// # Examples /// /// ``` /// use zerocopy::*; /// /// let source: u8 = 42; /// /// // Try to transmute the `source` to a `bool`. This will fail. /// let maybe_bool: Result<bool, ValidityError<u8, bool>> = try_transmute!(source); /// /// // Drop the error's source. /// let maybe_bool: Result<bool, ValidityError<(), bool>> = maybe_bool.map_err(|err| { /// err.map_src(drop) /// }); /// ``` #[inline] pubfn map_src<NewSrc>(self, f: impl FnOnce(Src) -> NewSrc) -> ValidityError<NewSrc, Dst> {
ValidityError { src: f(self.src), dst: SendSyncPhantomData::default() }
}
/// Converts the error into a general [`ConvertError`]. pub(crate) fn into<A, S>(self) -> ConvertError<A, S, Self> {
ConvertError::Validity(self)
}
/// Format extra details for a verbose, human-readable error message. /// /// This formatting may include potentially sensitive information. fn display_verbose_extras(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result where
Dst: KnownLayout,
{
f.write_str("Destination type: ")?;
f.write_str(core::any::type_name::<Dst>())?;
Ok(())
}
}
/// Produces a human-readable error message. /// /// The message differs between debug and release builds. When /// `debug_assertions` are enabled, this message is verbose and includes /// potentially sensitive information. impl<Src, Dst: ?Sized> fmt::Display for ValidityError<Src, Dst> where
Dst: KnownLayout + TryFromBytes,
{ #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("The conversion failed because the source bytes are not a valid value of the destination type.")?; if cfg!(debug_assertions) {
f.write_str("\n\n")?; self.display_verbose_extras(f)?;
}
Ok(())
}
}
/// The error type of reference conversions. /// /// Reference conversions, like [`FromBytes::ref_from_bytes`] may emit /// [alignment](AlignmentError) and [size](SizeError) errors. // Bounds on generic parameters are not enforced in type aliases, but they do // appear in rustdoc. #[allow(type_alias_bounds)] pubtype CastError<Src, Dst: ?Sized> =
ConvertError<AlignmentError<Src, Dst>, SizeError<Src, Dst>, Infallible>;
impl<Src, Dst: ?Sized> CastError<Src, Dst> { /// Produces the source underlying the failed conversion. #[inline] pubfn into_src(self) -> Src { matchself { Self::Alignment(e) => e.src, Self::Size(e) => e.src, Self::Validity(i) => match i {},
}
}
/// Sets the source value associated with the conversion error. pub(crate) fn with_src<NewSrc>(self, new_src: NewSrc) -> CastError<NewSrc, Dst> { matchself { Self::Alignment(e) => CastError::Alignment(e.with_src(new_src)), Self::Size(e) => CastError::Size(e.with_src(new_src)), Self::Validity(i) => match i {},
}
}
/// Maps the source value associated with the conversion error. /// /// This can help mitigate [issues with `Send`, `Sync` and `'static` /// bounds][self#send-sync-and-static]. /// /// # Examples /// /// ``` /// use zerocopy::*; /// /// let source: [u8; 3] = [0, 1, 2]; /// /// // Try to read a `u32` from `source`. This will fail because there are insufficient /// // bytes in `source`. /// let maybe_u32: Result<&u32, CastError<&[u8], u32>> = u32::ref_from_bytes(&source[..]); /// /// // Map the error's source to its size and address. /// let maybe_u32: Result<&u32, CastError<(usize, usize), u32>> = maybe_u32.map_err(|err| { /// err.map_src(|src| (src.len(), src.as_ptr() as usize)) /// }); /// ``` #[inline] pubfn map_src<NewSrc>(self, f: impl FnOnce(Src) -> NewSrc) -> CastError<NewSrc, Dst> { matchself { Self::Alignment(e) => CastError::Alignment(e.map_src(f)), Self::Size(e) => CastError::Size(e.map_src(f)), Self::Validity(i) => match i {},
}
}
/// Converts the error into a general [`ConvertError`]. pub(crate) fn into(self) -> TryCastError<Src, Dst> where
Dst: TryFromBytes,
{ matchself { Self::Alignment(e) => TryCastError::Alignment(e), Self::Size(e) => TryCastError::Size(e), Self::Validity(i) => match i {},
}
}
}
impl<Src, Dst: ?Sized + Unaligned> From<CastError<Src, Dst>> for SizeError<Src, Dst> { /// Infallibly extracts the [`SizeError`] from this `CastError` since `Dst` /// is unaligned. /// /// Since [`Dst: Unaligned`], it is impossible to encounter an alignment /// error, and so the only error that can be encountered at runtime is a /// [`SizeError`]. This method permits extracting that `SizeError` /// infallibly. /// /// [`Dst: Unaligned`]: crate::Unaligned /// /// # Examples /// /// ```rust /// use zerocopy::*; /// # use zerocopy_derive::*; /// /// #[derive(FromBytes, IntoBytes, KnownLayout, Immutable, Unaligned)] /// #[repr(C)] /// struct UdpHeader { /// src_port: [u8; 2], /// dst_port: [u8; 2], /// length: [u8; 2], /// checksum: [u8; 2], /// } /// /// #[derive(FromBytes, IntoBytes, KnownLayout, Immutable, Unaligned)] /// #[repr(C, packed)] /// struct UdpPacket { /// header: UdpHeader, /// body: [u8], /// } /// /// impl UdpPacket { /// pub fn parse(bytes: &[u8]) -> Result<&UdpPacket, SizeError<&[u8], UdpPacket>> { /// // Since `UdpPacket: Unaligned`, we can map the `CastError` to a `SizeError`. /// UdpPacket::ref_from_bytes(bytes).map_err(Into::into) /// } /// } /// ``` #[inline(always)] fn from(err: CastError<Src, Dst>) -> SizeError<Src, Dst> { match err { #[allow(unreachable_code)]
CastError::Alignment(e) => match Infallible::from(e) {},
CastError::Size(e) => e,
CastError::Validity(i) => match i {},
}
}
}
/// The error type of fallible reference conversions. /// /// Fallible reference conversions, like [`TryFromBytes::try_ref_from_bytes`] /// may emit [alignment](AlignmentError), [size](SizeError), and /// [validity](ValidityError) errors. // Bounds on generic parameters are not enforced in type aliases, but they do // appear in rustdoc. #[allow(type_alias_bounds)] pubtype TryCastError<Src, Dst: ?Sized + TryFromBytes> =
ConvertError<AlignmentError<Src, Dst>, SizeError<Src, Dst>, ValidityError<Src, Dst>>;
// FIXME(#1139): Remove the `TryFromBytes` here and in other downstream // locations (all the way to `ValidityError`) if we determine it's not necessary // for rich validity errors. impl<Src, Dst: ?Sized + TryFromBytes> TryCastError<Src, Dst> { /// Produces the source underlying the failed conversion. #[inline] pubfn into_src(self) -> Src { matchself { Self::Alignment(e) => e.src, Self::Size(e) => e.src, Self::Validity(e) => e.src,
}
}
/// Maps the source value associated with the conversion error. /// /// This can help mitigate [issues with `Send`, `Sync` and `'static` /// bounds][self#send-sync-and-static]. /// /// # Examples /// /// ``` /// use core::num::NonZeroU32; /// use zerocopy::*; /// /// let source: [u8; 3] = [0, 0, 0]; /// /// // Try to read a `NonZeroU32` from `source`. /// let maybe_u32: Result<&NonZeroU32, TryCastError<&[u8], NonZeroU32>> /// = NonZeroU32::try_ref_from_bytes(&source[..]); /// /// // Map the error's source to its size and address. /// let maybe_u32: Result<&NonZeroU32, TryCastError<(usize, usize), NonZeroU32>> = /// maybe_u32.map_err(|err| { /// err.map_src(|src| (src.len(), src.as_ptr() as usize)) /// }); /// ``` #[inline] pubfn map_src<NewSrc>(self, f: impl FnOnce(Src) -> NewSrc) -> TryCastError<NewSrc, Dst> { matchself { Self::Alignment(e) => TryCastError::Alignment(e.map_src(f)), Self::Size(e) => TryCastError::Size(e.map_src(f)), Self::Validity(e) => TryCastError::Validity(e.map_src(f)),
}
}
}
impl<Src, Dst: ?Sized + TryFromBytes> From<CastError<Src, Dst>> for TryCastError<Src, Dst> { #[inline] fn from(value: CastError<Src, Dst>) -> Self { match value {
CastError::Alignment(e) => Self::Alignment(e),
CastError::Size(e) => Self::Size(e),
CastError::Validity(i) => match i {},
}
}
}
/// The error type of fallible read-conversions. /// /// Fallible read-conversions, like [`TryFromBytes::try_read_from_bytes`] may emit /// [size](SizeError) and [validity](ValidityError) errors, but not alignment errors. // Bounds on generic parameters are not enforced in type aliases, but they do // appear in rustdoc. #[allow(type_alias_bounds)] pubtype TryReadError<Src, Dst: ?Sized + TryFromBytes> =
ConvertError<Infallible, SizeError<Src, Dst>, ValidityError<Src, Dst>>;
impl<Src, Dst: ?Sized + TryFromBytes> TryReadError<Src, Dst> { /// Produces the source underlying the failed conversion. #[inline] pubfn into_src(self) -> Src { matchself { Self::Alignment(i) => match i {}, Self::Size(e) => e.src, Self::Validity(e) => e.src,
}
}
/// Maps the source value associated with the conversion error. /// /// This can help mitigate [issues with `Send`, `Sync` and `'static` /// bounds][self#send-sync-and-static]. /// /// # Examples /// /// ``` /// use core::num::NonZeroU32; /// use zerocopy::*; /// /// let source: [u8; 3] = [0, 0, 0]; /// /// // Try to read a `NonZeroU32` from `source`. /// let maybe_u32: Result<NonZeroU32, TryReadError<&[u8], NonZeroU32>> /// = NonZeroU32::try_read_from_bytes(&source[..]); /// /// // Map the error's source to its size. /// let maybe_u32: Result<NonZeroU32, TryReadError<usize, NonZeroU32>> = /// maybe_u32.map_err(|err| { /// err.map_src(|src| src.len()) /// }); /// ``` #[inline] pubfn map_src<NewSrc>(self, f: impl FnOnce(Src) -> NewSrc) -> TryReadError<NewSrc, Dst> { matchself { Self::Alignment(i) => match i {}, Self::Size(e) => TryReadError::Size(e.map_src(f)), Self::Validity(e) => TryReadError::Validity(e.map_src(f)),
}
}
}
/// The error type of well-aligned, fallible casts. /// /// This is like [`TryCastError`], but for casts that are always well-aligned. /// It is identical to `TryCastError`, except that its alignment error is /// [`Infallible`]. /// /// As of this writing, none of zerocopy's API produces this error directly. /// However, it is useful since it permits users to infallibly discard alignment /// errors when they can prove statically that alignment errors are impossible. /// /// # Examples /// /// ``` /// use core::convert::Infallible; /// use zerocopy::*; /// # use zerocopy_derive::*; /// /// #[derive(TryFromBytes, KnownLayout, Unaligned, Immutable)] /// #[repr(C, packed)] /// struct Bools { /// one: bool, /// two: bool, /// many: [bool], /// } /// /// impl Bools { /// fn parse(bytes: &[u8]) -> Result<&Bools, AlignedTryCastError<&[u8], Bools>> { /// // Since `Bools: Unaligned`, we can infallibly discard /// // the alignment error. /// Bools::try_ref_from_bytes(bytes).map_err(Into::into) /// } /// } /// ``` #[allow(type_alias_bounds)] pubtype AlignedTryCastError<Src, Dst: ?Sized + TryFromBytes> =
ConvertError<Infallible, SizeError<Src, Dst>, ValidityError<Src, Dst>>;
/// The error type of a failed allocation. /// /// This type is intended to be deprecated in favor of the standard library's /// [`AllocError`] type once it is stabilized. When that happens, this type will /// be replaced by a type alias to the standard library type. We do not intend /// to treat this as a breaking change; users who wish to avoid breakage should /// avoid writing code which assumes that this is *not* such an alias. For /// example, implementing the same trait for both types will result in an impl /// conflict once this type is an alias. /// /// [`AllocError`]: https://doc.rust-lang.org/alloc/alloc/struct.AllocError.html #[derive(Copy, Clone, PartialEq, Eq, Debug)] pubstruct AllocError;
#[cfg(test)] mod tests { usesuper::*;
#[test] fn test_send_sync() { // Test that all error types are `Send + Sync` even if `Dst: !Send + // !Sync`.
let bytes = &aligned.bytes[1..]; let addr = crate::util::AsAddress::addr(bytes);
assert_eq!(
AlignmentError::<_, elain::Align::<8>>::new_checked(bytes).to_string(),
format!("The conversion failed because the address of the source is not a multiple of the alignment of the destination type.\n\
\nSource type: &[u8]\
\nSource address: 0x{:x} (a multiple of 1)\
\nDestination type: elain::Align<8>\
\nDestination alignment: 8", addr)
);
let bytes = &aligned.bytes[2..]; let addr = crate::util::AsAddress::addr(bytes);
assert_eq!(
AlignmentError::<_, elain::Align::<8>>::new_checked(bytes).to_string(),
format!("The conversion failed because the address of the source is not a multiple of the alignment of the destination type.\n\
\nSource type: &[u8]\
\nSource address: 0x{:x} (a multiple of 2)\
\nDestination type: elain::Align<8>\
\nDestination alignment: 8", addr)
);
let bytes = &aligned.bytes[3..]; let addr = crate::util::AsAddress::addr(bytes);
assert_eq!(
AlignmentError::<_, elain::Align::<8>>::new_checked(bytes).to_string(),
format!("The conversion failed because the address of the source is not a multiple of the alignment of the destination type.\n\
\nSource type: &[u8]\
\nSource address: 0x{:x} (a multiple of 1)\
\nDestination type: elain::Align<8>\
\nDestination alignment: 8", addr)
);
let bytes = &aligned.bytes[4..]; let addr = crate::util::AsAddress::addr(bytes);
assert_eq!(
AlignmentError::<_, elain::Align::<8>>::new_checked(bytes).to_string(),
format!("The conversion failed because the address of the source is not a multiple of the alignment of the destination type.\n\
\nSource type: &[u8]\
\nSource address: 0x{:x} (a multiple of 4)\
\nDestination type: elain::Align<8>\
\nDestination alignment: 8", addr)
);
}
#[test] fn size_display() {
assert_eq!(
SizeError::<_, [u8]>::new(&[0u8; 2][..]).to_string(), "The conversion failed because the source was incorrectly sized to complete the conversion into the destination type.\n\
\nSource type: &[u8]\
\nSource size: 2 bytes\
\nDestination type: [u8]"
);
assert_eq!(
SizeError::<_, [u8; 2]>::new(&[0u8; 1][..]).to_string(), "The conversion failed because the source was incorrectly sized to complete the conversion into the destination type.\n\
\nSource type: &[u8]\
\nSource size: 1 byte\
\nDestination size: 2 bytes\
\nDestination type: [u8; 2]"
);
}
#[test] fn validity_display() {
assert_eq!(
ValidityError::<_, bool>::new(&[2u8; 1][..]).to_string(), "The conversion failed because the source bytes are not a valid value of the destination type.\n\
\n\
Destination type: bool"
);
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.