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