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