Path: blob/main/crates/core/src/error/vtable.rs
3071 views
use crate::error::ptr::{MutPtr, OwnedPtr, SharedPtr};1use crate::error::{2ConcreteError, DynError, ErrorExt, OomOrDynErrorMut, OomOrDynErrorRef, OutOfMemory,3};4use core::{any::TypeId, fmt, ptr::NonNull};5use std_alloc::boxed::Box;67/// A vtable containing the `ErrorExt` methods for some type `T`.8///9/// This is used to create thin-pointer equivalents of `Box<dyn ErrorExt>`,10/// `&dyn ErrorExt`, and `&mut ErrorExt`, which would all otherwise be two words11/// in size.12///13/// # Safety14///15/// The safety contract for all vtable functions is the same:16///17/// * `SharedPtr<'_, DynError>`s must be valid for reading a `ConcreteError<T>`,18/// `MutPtr<'_, DynError>`s must additionally be valid for writing a19/// `ConcreteError<T>`, and `OwnedPtr<DynError>`s must additionally be valid20/// to deallocate with `ConcreteError<T>`'s layout.21///22/// * If a `OomOrDynError{Ref,Mut}` return value contains a `{Shared,Mut}Ptr<'_,23/// DynError>`, it must be valid for reading (and, in the case of `MutPtr`,24/// writing) `DynError`s.25#[repr(C)]26pub(crate) struct Vtable {27pub(crate) display: unsafe fn(SharedPtr<'_, DynError>, &mut fmt::Formatter<'_>) -> fmt::Result,28pub(crate) debug: unsafe fn(SharedPtr<'_, DynError>, &mut fmt::Formatter<'_>) -> fmt::Result,29pub(crate) source: unsafe fn(SharedPtr<'_, DynError>) -> Option<OomOrDynErrorRef<'_>>,30pub(crate) source_mut: unsafe fn(MutPtr<'_, DynError>) -> Option<OomOrDynErrorMut<'_>>,31pub(crate) is: unsafe fn(SharedPtr<'_, DynError>, TypeId) -> bool,32pub(crate) as_dyn_core_error:33unsafe fn(SharedPtr<'_, DynError>) -> &(dyn core::error::Error + Send + Sync + 'static),34pub(crate) into_boxed_dyn_core_error:35unsafe fn(36OwnedPtr<DynError>,37)38-> Result<Box<dyn core::error::Error + Send + Sync + 'static>, OutOfMemory>,39pub(crate) drop_and_deallocate: unsafe fn(OwnedPtr<DynError>),4041/// Additional safety requirement: the `NonNull<u8>` pointer must be valid42/// for writing a `T`.43///44/// Upon successful return, a `T` will have been written to that memory45/// block.46pub(crate) downcast: unsafe fn(OwnedPtr<DynError>, TypeId, NonNull<u8>),47}4849impl Vtable {50/// Get the `Vtable` of the `E: ErrorExt` type parameter.51pub(crate) fn of<E>() -> &'static Self52where53E: ErrorExt,54{55&Vtable {56display: display::<E>,57debug: debug::<E>,58source: source::<E>,59source_mut: source_mut::<E>,60is: is::<E>,61as_dyn_core_error: as_dyn_core_error::<E>,62into_boxed_dyn_core_error: into_boxed_dyn_core_error::<E>,63drop_and_deallocate: drop_and_deallocate::<E>,64downcast: downcast::<E>,65}66}67}6869unsafe fn display<E>(error: SharedPtr<'_, DynError>, f: &mut fmt::Formatter<'_>) -> fmt::Result70where71E: ErrorExt,72{73let error = error.cast::<ConcreteError<E>>();74// Safety: implied by all vtable functions' safety contract.75let error = unsafe { error.as_ref() };76fmt::Display::fmt(error.error.ext_as_dyn_core_error(), f)77}7879unsafe fn debug<E>(error: SharedPtr<'_, DynError>, f: &mut fmt::Formatter<'_>) -> fmt::Result80where81E: ErrorExt,82{83let error = error.cast::<ConcreteError<E>>();84// Safety: implied by all vtable functions' safety contract.85let error = unsafe { error.as_ref() };86fmt::Debug::fmt(error.error.ext_as_dyn_core_error(), f)87}8889unsafe fn source<E>(error: SharedPtr<'_, DynError>) -> Option<OomOrDynErrorRef<'_>>90where91E: ErrorExt,92{93let error = error.cast::<ConcreteError<E>>();94// Safety: implied by all vtable functions' safety contract.95let error = unsafe { error.as_ref() };96error.error.ext_source()97}9899unsafe fn source_mut<E>(error: MutPtr<'_, DynError>) -> Option<OomOrDynErrorMut<'_>>100where101E: ErrorExt,102{103let mut error = error.cast::<ConcreteError<E>>();104// Safety: implied by all vtable functions' safety contract.105let error = unsafe { error.as_mut() };106error.error.ext_source_mut()107}108109unsafe fn is<E>(error: SharedPtr<'_, DynError>, type_id: TypeId) -> bool110where111E: ErrorExt,112{113let error = error.cast::<ConcreteError<E>>();114// Safety: implied by all vtable functions' safety contract.115let error = unsafe { error.as_ref() };116error.error.ext_is(type_id)117}118119unsafe fn as_dyn_core_error<E>(120error: SharedPtr<'_, DynError>,121) -> &(dyn core::error::Error + Send + Sync + 'static)122where123E: ErrorExt,124{125let error = error.cast::<ConcreteError<E>>();126// Safety: implied by all vtable functions' safety contract.127let error = unsafe { error.as_ref() };128error.error.ext_as_dyn_core_error()129}130131unsafe fn into_boxed_dyn_core_error<E>(132error: OwnedPtr<DynError>,133) -> Result<Box<dyn core::error::Error + Send + Sync + 'static>, OutOfMemory>134where135E: ErrorExt,136{137let error = error.cast::<ConcreteError<E>>();138// Safety: implied by all vtable functions' safety contract.139let error = unsafe { error.into_box() };140error.error.ext_into_boxed_dyn_core_error()141}142143unsafe fn drop_and_deallocate<E>(error: OwnedPtr<DynError>)144where145E: ErrorExt,146{147let error = error.cast::<ConcreteError<E>>();148// Safety: implied by all vtable functions' safety contract.149let _ = unsafe { error.into_box() };150}151152unsafe fn downcast<E>(error: OwnedPtr<DynError>, type_id: TypeId, ret_ptr: NonNull<u8>)153where154E: ErrorExt,155{156let error = error.cast::<ConcreteError<E>>();157// Safety: implied by all vtable functions' safety contract.158let mut error = unsafe { error.into_box() };159160if error.error.ext_is(type_id) {161// Safety: Implied by `downcast`'s additional safety safety requirement.162unsafe {163error.error.ext_move(ret_ptr);164}165} else {166let source = error167.error168.ext_take_source()169.expect("must have a source up the chain if `E` is not our target type");170// Safety: implied by downcast's additional safety requirement.171unsafe {172source.downcast(type_id, ret_ptr);173}174}175}176177178