18325e1ecSAlex Crichton use crate::error::ptr::{MutPtr, OwnedPtr, SharedPtr};
2*5afb6030SNick Fitzgerald use crate::error::{ConcreteError, DynError, Error, ErrorExt, OutOfMemory};
38325e1ecSAlex Crichton use core::{any::TypeId, fmt, ptr::NonNull};
48325e1ecSAlex Crichton use std_alloc::boxed::Box;
58325e1ecSAlex Crichton 
68325e1ecSAlex Crichton /// A vtable containing the `ErrorExt` methods for some type `T`.
78325e1ecSAlex Crichton ///
88325e1ecSAlex Crichton /// This is used to create thin-pointer equivalents of `Box<dyn ErrorExt>`,
98325e1ecSAlex Crichton /// `&dyn ErrorExt`, and `&mut ErrorExt`, which would all otherwise be two words
108325e1ecSAlex Crichton /// in size.
118325e1ecSAlex Crichton ///
128325e1ecSAlex Crichton /// # Safety
138325e1ecSAlex Crichton ///
148325e1ecSAlex Crichton /// The safety contract for all vtable functions is the same:
158325e1ecSAlex Crichton ///
168325e1ecSAlex Crichton /// * `SharedPtr<'_, DynError>`s must be valid for reading a `ConcreteError<T>`,
178325e1ecSAlex Crichton ///   `MutPtr<'_, DynError>`s must additionally be valid for writing a
188325e1ecSAlex Crichton ///   `ConcreteError<T>`, and `OwnedPtr<DynError>`s must additionally be valid
198325e1ecSAlex Crichton ///   to deallocate with `ConcreteError<T>`'s layout.
208325e1ecSAlex Crichton ///
218325e1ecSAlex Crichton /// * If a `OomOrDynError{Ref,Mut}` return value contains a `{Shared,Mut}Ptr<'_,
228325e1ecSAlex Crichton ///   DynError>`, it must be valid for reading (and, in the case of `MutPtr`,
238325e1ecSAlex Crichton ///   writing) `DynError`s.
248325e1ecSAlex Crichton #[repr(C)]
258325e1ecSAlex Crichton pub(crate) struct Vtable {
268325e1ecSAlex Crichton     pub(crate) display: unsafe fn(SharedPtr<'_, DynError>, &mut fmt::Formatter<'_>) -> fmt::Result,
278325e1ecSAlex Crichton     pub(crate) debug: unsafe fn(SharedPtr<'_, DynError>, &mut fmt::Formatter<'_>) -> fmt::Result,
28*5afb6030SNick Fitzgerald     pub(crate) source: unsafe fn(SharedPtr<'_, DynError>) -> Option<&Error>,
29*5afb6030SNick Fitzgerald     pub(crate) source_mut: unsafe fn(MutPtr<'_, DynError>) -> Option<&mut Error>,
308325e1ecSAlex Crichton     pub(crate) is: unsafe fn(SharedPtr<'_, DynError>, TypeId) -> bool,
318325e1ecSAlex Crichton     pub(crate) as_dyn_core_error:
328325e1ecSAlex Crichton         unsafe fn(SharedPtr<'_, DynError>) -> &(dyn core::error::Error + Send + Sync + 'static),
338325e1ecSAlex Crichton     pub(crate) into_boxed_dyn_core_error:
348325e1ecSAlex Crichton         unsafe fn(
358325e1ecSAlex Crichton             OwnedPtr<DynError>,
368325e1ecSAlex Crichton         )
378325e1ecSAlex Crichton             -> Result<Box<dyn core::error::Error + Send + Sync + 'static>, OutOfMemory>,
388325e1ecSAlex Crichton     pub(crate) drop_and_deallocate: unsafe fn(OwnedPtr<DynError>),
398325e1ecSAlex Crichton 
408325e1ecSAlex Crichton     /// Additional safety requirement: the `NonNull<u8>` pointer must be valid
418325e1ecSAlex Crichton     /// for writing a `T`.
428325e1ecSAlex Crichton     ///
438325e1ecSAlex Crichton     /// Upon successful return, a `T` will have been written to that memory
448325e1ecSAlex Crichton     /// block.
45*5afb6030SNick Fitzgerald     pub(crate) move_into: unsafe fn(OwnedPtr<DynError>, NonNull<u8>),
464fd25c07SAlex Crichton 
474fd25c07SAlex Crichton     /// Conversion into `anyhow::Error` from `Box<Self>`.
484fd25c07SAlex Crichton     #[cfg(feature = "anyhow")]
494fd25c07SAlex Crichton     pub(crate) into_anyhow: unsafe fn(OwnedPtr<DynError>) -> anyhow::Error,
508325e1ecSAlex Crichton }
518325e1ecSAlex Crichton 
528325e1ecSAlex Crichton impl Vtable {
538325e1ecSAlex Crichton     /// Get the `Vtable` of the `E: ErrorExt` type parameter.
of<E>() -> &'static Self where E: ErrorExt,548325e1ecSAlex Crichton     pub(crate) fn of<E>() -> &'static Self
558325e1ecSAlex Crichton     where
568325e1ecSAlex Crichton         E: ErrorExt,
578325e1ecSAlex Crichton     {
588325e1ecSAlex Crichton         &Vtable {
598325e1ecSAlex Crichton             display: display::<E>,
608325e1ecSAlex Crichton             debug: debug::<E>,
618325e1ecSAlex Crichton             source: source::<E>,
628325e1ecSAlex Crichton             source_mut: source_mut::<E>,
638325e1ecSAlex Crichton             is: is::<E>,
648325e1ecSAlex Crichton             as_dyn_core_error: as_dyn_core_error::<E>,
658325e1ecSAlex Crichton             into_boxed_dyn_core_error: into_boxed_dyn_core_error::<E>,
668325e1ecSAlex Crichton             drop_and_deallocate: drop_and_deallocate::<E>,
67*5afb6030SNick Fitzgerald             move_into: move_into::<E>,
684fd25c07SAlex Crichton             #[cfg(feature = "anyhow")]
694fd25c07SAlex Crichton             into_anyhow: into_anyhow::<E>,
708325e1ecSAlex Crichton         }
718325e1ecSAlex Crichton     }
728325e1ecSAlex Crichton }
738325e1ecSAlex Crichton 
display<E>(error: SharedPtr<'_, DynError>, f: &mut fmt::Formatter<'_>) -> fmt::Result where E: ErrorExt,748325e1ecSAlex Crichton unsafe fn display<E>(error: SharedPtr<'_, DynError>, f: &mut fmt::Formatter<'_>) -> fmt::Result
758325e1ecSAlex Crichton where
768325e1ecSAlex Crichton     E: ErrorExt,
778325e1ecSAlex Crichton {
788325e1ecSAlex Crichton     let error = error.cast::<ConcreteError<E>>();
798325e1ecSAlex Crichton     // Safety: implied by all vtable functions' safety contract.
808325e1ecSAlex Crichton     let error = unsafe { error.as_ref() };
818325e1ecSAlex Crichton     fmt::Display::fmt(error.error.ext_as_dyn_core_error(), f)
828325e1ecSAlex Crichton }
838325e1ecSAlex Crichton 
debug<E>(error: SharedPtr<'_, DynError>, f: &mut fmt::Formatter<'_>) -> fmt::Result where E: ErrorExt,848325e1ecSAlex Crichton unsafe fn debug<E>(error: SharedPtr<'_, DynError>, f: &mut fmt::Formatter<'_>) -> fmt::Result
858325e1ecSAlex Crichton where
868325e1ecSAlex Crichton     E: ErrorExt,
878325e1ecSAlex Crichton {
888325e1ecSAlex Crichton     let error = error.cast::<ConcreteError<E>>();
898325e1ecSAlex Crichton     // Safety: implied by all vtable functions' safety contract.
908325e1ecSAlex Crichton     let error = unsafe { error.as_ref() };
918325e1ecSAlex Crichton     fmt::Debug::fmt(error.error.ext_as_dyn_core_error(), f)
928325e1ecSAlex Crichton }
938325e1ecSAlex Crichton 
source<E>(error: SharedPtr<'_, DynError>) -> Option<&Error> where E: ErrorExt,94*5afb6030SNick Fitzgerald unsafe fn source<E>(error: SharedPtr<'_, DynError>) -> Option<&Error>
958325e1ecSAlex Crichton where
968325e1ecSAlex Crichton     E: ErrorExt,
978325e1ecSAlex Crichton {
988325e1ecSAlex Crichton     let error = error.cast::<ConcreteError<E>>();
998325e1ecSAlex Crichton     // Safety: implied by all vtable functions' safety contract.
1008325e1ecSAlex Crichton     let error = unsafe { error.as_ref() };
1018325e1ecSAlex Crichton     error.error.ext_source()
1028325e1ecSAlex Crichton }
1038325e1ecSAlex Crichton 
source_mut<E>(error: MutPtr<'_, DynError>) -> Option<&mut Error> where E: ErrorExt,104*5afb6030SNick Fitzgerald unsafe fn source_mut<E>(error: MutPtr<'_, DynError>) -> Option<&mut Error>
1058325e1ecSAlex Crichton where
1068325e1ecSAlex Crichton     E: ErrorExt,
1078325e1ecSAlex Crichton {
1088325e1ecSAlex Crichton     let mut error = error.cast::<ConcreteError<E>>();
1098325e1ecSAlex Crichton     // Safety: implied by all vtable functions' safety contract.
1108325e1ecSAlex Crichton     let error = unsafe { error.as_mut() };
1118325e1ecSAlex Crichton     error.error.ext_source_mut()
1128325e1ecSAlex Crichton }
1138325e1ecSAlex Crichton 
is<E>(error: SharedPtr<'_, DynError>, type_id: TypeId) -> bool where E: ErrorExt,1148325e1ecSAlex Crichton unsafe fn is<E>(error: SharedPtr<'_, DynError>, type_id: TypeId) -> bool
1158325e1ecSAlex Crichton where
1168325e1ecSAlex Crichton     E: ErrorExt,
1178325e1ecSAlex Crichton {
1188325e1ecSAlex Crichton     let error = error.cast::<ConcreteError<E>>();
1198325e1ecSAlex Crichton     // Safety: implied by all vtable functions' safety contract.
1208325e1ecSAlex Crichton     let error = unsafe { error.as_ref() };
1218325e1ecSAlex Crichton     error.error.ext_is(type_id)
1228325e1ecSAlex Crichton }
1238325e1ecSAlex Crichton 
as_dyn_core_error<E>( error: SharedPtr<'_, DynError>, ) -> &(dyn core::error::Error + Send + Sync + 'static) where E: ErrorExt,1248325e1ecSAlex Crichton unsafe fn as_dyn_core_error<E>(
1258325e1ecSAlex Crichton     error: SharedPtr<'_, DynError>,
1268325e1ecSAlex Crichton ) -> &(dyn core::error::Error + Send + Sync + 'static)
1278325e1ecSAlex Crichton where
1288325e1ecSAlex Crichton     E: ErrorExt,
1298325e1ecSAlex Crichton {
1308325e1ecSAlex Crichton     let error = error.cast::<ConcreteError<E>>();
1318325e1ecSAlex Crichton     // Safety: implied by all vtable functions' safety contract.
1328325e1ecSAlex Crichton     let error = unsafe { error.as_ref() };
1338325e1ecSAlex Crichton     error.error.ext_as_dyn_core_error()
1348325e1ecSAlex Crichton }
1358325e1ecSAlex Crichton 
into_boxed_dyn_core_error<E>( error: OwnedPtr<DynError>, ) -> Result<Box<dyn core::error::Error + Send + Sync + 'static>, OutOfMemory> where E: ErrorExt,1368325e1ecSAlex Crichton unsafe fn into_boxed_dyn_core_error<E>(
1378325e1ecSAlex Crichton     error: OwnedPtr<DynError>,
1388325e1ecSAlex Crichton ) -> Result<Box<dyn core::error::Error + Send + Sync + 'static>, OutOfMemory>
1398325e1ecSAlex Crichton where
1408325e1ecSAlex Crichton     E: ErrorExt,
1418325e1ecSAlex Crichton {
1428325e1ecSAlex Crichton     let error = error.cast::<ConcreteError<E>>();
1438325e1ecSAlex Crichton     // Safety: implied by all vtable functions' safety contract.
1448325e1ecSAlex Crichton     let error = unsafe { error.into_box() };
1458325e1ecSAlex Crichton     error.error.ext_into_boxed_dyn_core_error()
1468325e1ecSAlex Crichton }
1478325e1ecSAlex Crichton 
drop_and_deallocate<E>(error: OwnedPtr<DynError>) where E: ErrorExt,1488325e1ecSAlex Crichton unsafe fn drop_and_deallocate<E>(error: OwnedPtr<DynError>)
1498325e1ecSAlex Crichton where
1508325e1ecSAlex Crichton     E: ErrorExt,
1518325e1ecSAlex Crichton {
1528325e1ecSAlex Crichton     let error = error.cast::<ConcreteError<E>>();
1538325e1ecSAlex Crichton     // Safety: implied by all vtable functions' safety contract.
1548325e1ecSAlex Crichton     let _ = unsafe { error.into_box() };
1558325e1ecSAlex Crichton }
1568325e1ecSAlex Crichton 
move_into<E>(error: OwnedPtr<DynError>, ret_ptr: NonNull<u8>) where E: ErrorExt,157*5afb6030SNick Fitzgerald unsafe fn move_into<E>(error: OwnedPtr<DynError>, ret_ptr: NonNull<u8>)
1588325e1ecSAlex Crichton where
1598325e1ecSAlex Crichton     E: ErrorExt,
1608325e1ecSAlex Crichton {
1618325e1ecSAlex Crichton     let error = error.cast::<ConcreteError<E>>();
1628325e1ecSAlex Crichton     // Safety: implied by all vtable functions' safety contract.
163*5afb6030SNick Fitzgerald     let error = unsafe { error.into_box() };
164*5afb6030SNick Fitzgerald     // Safety: Implied by `move`'s additional safety safety requirement.
1658325e1ecSAlex Crichton     unsafe {
1668325e1ecSAlex Crichton         error.error.ext_move(ret_ptr);
1678325e1ecSAlex Crichton     }
1688325e1ecSAlex Crichton }
1694fd25c07SAlex Crichton 
1704fd25c07SAlex Crichton #[cfg(feature = "anyhow")]
into_anyhow<E>(error: OwnedPtr<DynError>) -> anyhow::Error where E: ErrorExt,1714fd25c07SAlex Crichton unsafe fn into_anyhow<E>(error: OwnedPtr<DynError>) -> anyhow::Error
1724fd25c07SAlex Crichton where
1734fd25c07SAlex Crichton     E: ErrorExt,
1744fd25c07SAlex Crichton {
1754fd25c07SAlex Crichton     let error = error.cast::<ConcreteError<E>>();
1764fd25c07SAlex Crichton     // Safety: implied by all vtable functions' safety contract.
1774fd25c07SAlex Crichton     let error = unsafe { error.into_box() };
1784fd25c07SAlex Crichton     error.error.ext_into_anyhow()
1794fd25c07SAlex Crichton }
180