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