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