1 use crate::error::ptr::{MutPtr, OwnedPtr, SharedPtr}; 2 use crate::error::{ 3 ConcreteError, DynError, ErrorExt, OomOrDynErrorMut, OomOrDynErrorRef, OutOfMemory, 4 }; 5 use core::{any::TypeId, fmt, ptr::NonNull}; 6 use std_alloc::boxed::Box; 7 8 /// A vtable containing the `ErrorExt` methods for some type `T`. 9 /// 10 /// This is used to create thin-pointer equivalents of `Box<dyn ErrorExt>`, 11 /// `&dyn ErrorExt`, and `&mut ErrorExt`, which would all otherwise be two words 12 /// in size. 13 /// 14 /// # Safety 15 /// 16 /// The safety contract for all vtable functions is the same: 17 /// 18 /// * `SharedPtr<'_, DynError>`s must be valid for reading a `ConcreteError<T>`, 19 /// `MutPtr<'_, DynError>`s must additionally be valid for writing a 20 /// `ConcreteError<T>`, and `OwnedPtr<DynError>`s must additionally be valid 21 /// to deallocate with `ConcreteError<T>`'s layout. 22 /// 23 /// * If a `OomOrDynError{Ref,Mut}` return value contains a `{Shared,Mut}Ptr<'_, 24 /// DynError>`, it must be valid for reading (and, in the case of `MutPtr`, 25 /// writing) `DynError`s. 26 #[repr(C)] 27 pub(crate) struct Vtable { 28 pub(crate) display: unsafe fn(SharedPtr<'_, DynError>, &mut fmt::Formatter<'_>) -> fmt::Result, 29 pub(crate) debug: unsafe fn(SharedPtr<'_, DynError>, &mut fmt::Formatter<'_>) -> fmt::Result, 30 pub(crate) source: unsafe fn(SharedPtr<'_, DynError>) -> Option<OomOrDynErrorRef<'_>>, 31 pub(crate) source_mut: unsafe fn(MutPtr<'_, DynError>) -> Option<OomOrDynErrorMut<'_>>, 32 pub(crate) is: unsafe fn(SharedPtr<'_, DynError>, TypeId) -> bool, 33 pub(crate) as_dyn_core_error: 34 unsafe fn(SharedPtr<'_, DynError>) -> &(dyn core::error::Error + Send + Sync + 'static), 35 pub(crate) into_boxed_dyn_core_error: 36 unsafe fn( 37 OwnedPtr<DynError>, 38 ) 39 -> Result<Box<dyn core::error::Error + Send + Sync + 'static>, OutOfMemory>, 40 pub(crate) drop_and_deallocate: unsafe fn(OwnedPtr<DynError>), 41 42 /// Additional safety requirement: the `NonNull<u8>` pointer must be valid 43 /// for writing a `T`. 44 /// 45 /// Upon successful return, a `T` will have been written to that memory 46 /// block. 47 pub(crate) downcast: unsafe fn(OwnedPtr<DynError>, TypeId, NonNull<u8>), 48 } 49 50 impl Vtable { 51 /// Get the `Vtable` of the `E: ErrorExt` type parameter. 52 pub(crate) fn of<E>() -> &'static Self 53 where 54 E: ErrorExt, 55 { 56 &Vtable { 57 display: display::<E>, 58 debug: debug::<E>, 59 source: source::<E>, 60 source_mut: source_mut::<E>, 61 is: is::<E>, 62 as_dyn_core_error: as_dyn_core_error::<E>, 63 into_boxed_dyn_core_error: into_boxed_dyn_core_error::<E>, 64 drop_and_deallocate: drop_and_deallocate::<E>, 65 downcast: downcast::<E>, 66 } 67 } 68 } 69 70 unsafe fn display<E>(error: SharedPtr<'_, DynError>, f: &mut fmt::Formatter<'_>) -> fmt::Result 71 where 72 E: ErrorExt, 73 { 74 let error = error.cast::<ConcreteError<E>>(); 75 // Safety: implied by all vtable functions' safety contract. 76 let error = unsafe { error.as_ref() }; 77 fmt::Display::fmt(error.error.ext_as_dyn_core_error(), f) 78 } 79 80 unsafe fn debug<E>(error: SharedPtr<'_, DynError>, f: &mut fmt::Formatter<'_>) -> fmt::Result 81 where 82 E: ErrorExt, 83 { 84 let error = error.cast::<ConcreteError<E>>(); 85 // Safety: implied by all vtable functions' safety contract. 86 let error = unsafe { error.as_ref() }; 87 fmt::Debug::fmt(error.error.ext_as_dyn_core_error(), f) 88 } 89 90 unsafe fn source<E>(error: SharedPtr<'_, DynError>) -> Option<OomOrDynErrorRef<'_>> 91 where 92 E: ErrorExt, 93 { 94 let error = error.cast::<ConcreteError<E>>(); 95 // Safety: implied by all vtable functions' safety contract. 96 let error = unsafe { error.as_ref() }; 97 error.error.ext_source() 98 } 99 100 unsafe fn source_mut<E>(error: MutPtr<'_, DynError>) -> Option<OomOrDynErrorMut<'_>> 101 where 102 E: ErrorExt, 103 { 104 let mut error = error.cast::<ConcreteError<E>>(); 105 // Safety: implied by all vtable functions' safety contract. 106 let error = unsafe { error.as_mut() }; 107 error.error.ext_source_mut() 108 } 109 110 unsafe fn is<E>(error: SharedPtr<'_, DynError>, type_id: TypeId) -> bool 111 where 112 E: ErrorExt, 113 { 114 let error = error.cast::<ConcreteError<E>>(); 115 // Safety: implied by all vtable functions' safety contract. 116 let error = unsafe { error.as_ref() }; 117 error.error.ext_is(type_id) 118 } 119 120 unsafe fn as_dyn_core_error<E>( 121 error: SharedPtr<'_, DynError>, 122 ) -> &(dyn core::error::Error + Send + Sync + 'static) 123 where 124 E: ErrorExt, 125 { 126 let error = error.cast::<ConcreteError<E>>(); 127 // Safety: implied by all vtable functions' safety contract. 128 let error = unsafe { error.as_ref() }; 129 error.error.ext_as_dyn_core_error() 130 } 131 132 unsafe fn into_boxed_dyn_core_error<E>( 133 error: OwnedPtr<DynError>, 134 ) -> Result<Box<dyn core::error::Error + Send + Sync + 'static>, OutOfMemory> 135 where 136 E: ErrorExt, 137 { 138 let error = error.cast::<ConcreteError<E>>(); 139 // Safety: implied by all vtable functions' safety contract. 140 let error = unsafe { error.into_box() }; 141 error.error.ext_into_boxed_dyn_core_error() 142 } 143 144 unsafe fn drop_and_deallocate<E>(error: OwnedPtr<DynError>) 145 where 146 E: ErrorExt, 147 { 148 let error = error.cast::<ConcreteError<E>>(); 149 // Safety: implied by all vtable functions' safety contract. 150 let _ = unsafe { error.into_box() }; 151 } 152 153 unsafe fn downcast<E>(error: OwnedPtr<DynError>, type_id: TypeId, ret_ptr: NonNull<u8>) 154 where 155 E: ErrorExt, 156 { 157 let error = error.cast::<ConcreteError<E>>(); 158 // Safety: implied by all vtable functions' safety contract. 159 let mut error = unsafe { error.into_box() }; 160 161 if error.error.ext_is(type_id) { 162 // Safety: Implied by `downcast`'s additional safety safety requirement. 163 unsafe { 164 error.error.ext_move(ret_ptr); 165 } 166 } else { 167 let source = error 168 .error 169 .ext_take_source() 170 .expect("must have a source up the chain if `E` is not our target type"); 171 // Safety: implied by downcast's additional safety requirement. 172 unsafe { 173 source.downcast(type_id, ret_ptr); 174 } 175 } 176 } 177