Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/crates/core/src/error/vtable.rs
3071 views
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
178