|
| 1 | +//! NB: These functions are not used any more by the latest version of the |
| 2 | +//! bindings generator for Rust. These functions are provided for historical |
| 3 | +//! compatibility with previous bindings generators before the 0.20.0 version |
| 4 | +//! of wit-bindgen. |
| 5 | +//! |
| 6 | +//! Once `cargo component` has updated to `wit-bindgen` 0.20.0+ and has been |
| 7 | +//! there for awhile this file should be removed. |
| 8 | +
|
| 9 | +extern crate alloc as alloc_crate; |
| 10 | + |
| 11 | +use alloc_crate::alloc::Layout; |
| 12 | +use alloc_crate::boxed::Box; |
| 13 | +use alloc_crate::string::String; |
| 14 | +use alloc_crate::vec::Vec; |
| 15 | +use core::fmt; |
| 16 | +use core::marker; |
| 17 | +use core::ops::{Deref, DerefMut}; |
| 18 | +use core::sync::atomic::{AtomicU32, Ordering::Relaxed}; |
| 19 | + |
| 20 | +pub use alloc_crate::{alloc, boxed, string, vec}; |
| 21 | + |
| 22 | +/// Provide a hook for generated export functions to run static |
| 23 | +/// constructors at most once. wit-bindgen-rust generates a call to this |
| 24 | +/// function at the start of all component export functions. Importantly, |
| 25 | +/// it is not called as part of `cabi_realloc`, which is a *core* export |
| 26 | +/// func, but may not execute ctors, because the environment ctor in |
| 27 | +/// wasi-libc (before rust 1.69.0) calls an import func, which is not |
| 28 | +/// permitted by the Component Model when inside realloc. |
| 29 | +/// |
| 30 | +/// We intend to remove this once rust 1.69.0 stabilizes. |
| 31 | +#[cfg(target_arch = "wasm32")] |
| 32 | +pub fn run_ctors_once() { |
| 33 | + static mut RUN: bool = false; |
| 34 | + unsafe { |
| 35 | + if !RUN { |
| 36 | + // This function is synthesized by `wasm-ld` to run all static |
| 37 | + // constructors. wasm-ld will either provide an implementation |
| 38 | + // of this symbol, or synthesize a wrapper around each |
| 39 | + // exported function to (unconditionally) run ctors. By using |
| 40 | + // this function, the linked module is opting into "manually" |
| 41 | + // running ctors. |
| 42 | + extern "C" { |
| 43 | + fn __wasm_call_ctors(); |
| 44 | + } |
| 45 | + __wasm_call_ctors(); |
| 46 | + RUN = true; |
| 47 | + } |
| 48 | + } |
| 49 | +} |
| 50 | + |
| 51 | +pub unsafe fn dealloc(ptr: i32, size: usize, align: usize) { |
| 52 | + if size == 0 { |
| 53 | + return; |
| 54 | + } |
| 55 | + let layout = Layout::from_size_align_unchecked(size, align); |
| 56 | + alloc_crate::alloc::dealloc(ptr as *mut u8, layout); |
| 57 | +} |
| 58 | + |
| 59 | +macro_rules! as_traits { |
| 60 | + ($(($trait_:ident $func:ident $ty:ident <=> $($tys:ident)*))*) => ($( |
| 61 | + pub fn $func<T: $trait_>(t: T) -> $ty { |
| 62 | + t.$func() |
| 63 | + } |
| 64 | + |
| 65 | + pub trait $trait_ { |
| 66 | + fn $func(self) -> $ty; |
| 67 | + } |
| 68 | + |
| 69 | + impl<'a, T: Copy + $trait_> $trait_ for &'a T { |
| 70 | + fn $func(self) -> $ty{ |
| 71 | + (*self).$func() |
| 72 | + } |
| 73 | + } |
| 74 | + |
| 75 | + $( |
| 76 | + impl $trait_ for $tys { |
| 77 | + #[inline] |
| 78 | + fn $func(self) -> $ty { |
| 79 | + self as $ty |
| 80 | + } |
| 81 | + } |
| 82 | + )* |
| 83 | + |
| 84 | + )*) |
| 85 | +} |
| 86 | + |
| 87 | +as_traits! { |
| 88 | + (AsI64 as_i64 i64 <=> i64 u64) |
| 89 | + (AsI32 as_i32 i32 <=> i32 u32 i16 u16 i8 u8 char usize) |
| 90 | + (AsF32 as_f32 f32 <=> f32) |
| 91 | + (AsF64 as_f64 f64 <=> f64) |
| 92 | +} |
| 93 | + |
| 94 | +pub unsafe fn string_lift(bytes: Vec<u8>) -> String { |
| 95 | + if cfg!(debug_assertions) { |
| 96 | + String::from_utf8(bytes).unwrap() |
| 97 | + } else { |
| 98 | + String::from_utf8_unchecked(bytes) |
| 99 | + } |
| 100 | +} |
| 101 | + |
| 102 | +pub unsafe fn invalid_enum_discriminant<T>() -> T { |
| 103 | + if cfg!(debug_assertions) { |
| 104 | + panic!("invalid enum discriminant") |
| 105 | + } else { |
| 106 | + core::hint::unreachable_unchecked() |
| 107 | + } |
| 108 | +} |
| 109 | + |
| 110 | +pub unsafe fn char_lift(val: u32) -> char { |
| 111 | + if cfg!(debug_assertions) { |
| 112 | + core::char::from_u32(val).unwrap() |
| 113 | + } else { |
| 114 | + core::char::from_u32_unchecked(val) |
| 115 | + } |
| 116 | +} |
| 117 | + |
| 118 | +pub unsafe fn bool_lift(val: u8) -> bool { |
| 119 | + if cfg!(debug_assertions) { |
| 120 | + match val { |
| 121 | + 0 => false, |
| 122 | + 1 => true, |
| 123 | + _ => panic!("invalid bool discriminant"), |
| 124 | + } |
| 125 | + } else { |
| 126 | + core::mem::transmute::<u8, bool>(val) |
| 127 | + } |
| 128 | +} |
| 129 | + |
| 130 | +type RawRep<T> = Option<T>; |
| 131 | + |
| 132 | +/// A type which represents a component model resource, either imported or |
| 133 | +/// exported into this component. |
| 134 | +/// |
| 135 | +/// This is a low-level wrapper which handles the lifetime of the resource |
| 136 | +/// (namely this has a destructor). The `T` provided defines the component model |
| 137 | +/// intrinsics that this wrapper uses. |
| 138 | +/// |
| 139 | +/// One of the chief purposes of this type is to provide `Deref` implementations |
| 140 | +/// to access the underlying data when it is owned. |
| 141 | +/// |
| 142 | +/// This type is primarily used in generated code for exported and imported |
| 143 | +/// resources. |
| 144 | +#[repr(transparent)] |
| 145 | +pub struct Resource<T: WasmResource> { |
| 146 | + // NB: This would ideally be `u32` but it is not. The fact that this has |
| 147 | + // interior mutability is not exposed in the API of this type except for the |
| 148 | + // `take_handle` method which is supposed to in theory be private. |
| 149 | + // |
| 150 | + // This represents, almost all the time, a valid handle value. When it's |
| 151 | + // invalid it's stored as `u32::MAX`. |
| 152 | + handle: AtomicU32, |
| 153 | + _marker: marker::PhantomData<Box<T>>, |
| 154 | +} |
| 155 | + |
| 156 | +/// A trait which all wasm resources implement, namely providing the ability to |
| 157 | +/// drop a resource. |
| 158 | +/// |
| 159 | +/// This generally is implemented by generated code, not user-facing code. |
| 160 | +pub unsafe trait WasmResource { |
| 161 | + /// Invokes the `[resource-drop]...` intrinsic. |
| 162 | + unsafe fn drop(handle: u32); |
| 163 | +} |
| 164 | + |
| 165 | +/// A trait which extends [`WasmResource`] used for Rust-defined resources, or |
| 166 | +/// those exported from this component. |
| 167 | +/// |
| 168 | +/// This generally is implemented by generated code, not user-facing code. |
| 169 | +pub unsafe trait RustResource: WasmResource { |
| 170 | + /// Invokes the `[resource-new]...` intrinsic. |
| 171 | + unsafe fn new(rep: usize) -> u32; |
| 172 | + /// Invokes the `[resource-rep]...` intrinsic. |
| 173 | + unsafe fn rep(handle: u32) -> usize; |
| 174 | +} |
| 175 | + |
| 176 | +impl<T: WasmResource> Resource<T> { |
| 177 | + #[doc(hidden)] |
| 178 | + pub unsafe fn from_handle(handle: u32) -> Self { |
| 179 | + debug_assert!(handle != u32::MAX); |
| 180 | + Self { |
| 181 | + handle: AtomicU32::new(handle), |
| 182 | + _marker: marker::PhantomData, |
| 183 | + } |
| 184 | + } |
| 185 | + |
| 186 | + /// Takes ownership of the handle owned by `resource`. |
| 187 | + /// |
| 188 | + /// Note that this ideally would be `into_handle` taking `Resource<T>` by |
| 189 | + /// ownership. The code generator does not enable that in all situations, |
| 190 | + /// unfortunately, so this is provided instead. |
| 191 | + /// |
| 192 | + /// Also note that `take_handle` is in theory only ever called on values |
| 193 | + /// owned by a generated function. For example a generated function might |
| 194 | + /// take `Resource<T>` as an argument but then call `take_handle` on a |
| 195 | + /// reference to that argument. In that sense the dynamic nature of |
| 196 | + /// `take_handle` should only be exposed internally to generated code, not |
| 197 | + /// to user code. |
| 198 | + #[doc(hidden)] |
| 199 | + pub fn take_handle(resource: &Resource<T>) -> u32 { |
| 200 | + resource.handle.swap(u32::MAX, Relaxed) |
| 201 | + } |
| 202 | + |
| 203 | + #[doc(hidden)] |
| 204 | + pub fn handle(resource: &Resource<T>) -> u32 { |
| 205 | + resource.handle.load(Relaxed) |
| 206 | + } |
| 207 | + |
| 208 | + /// Creates a new Rust-defined resource from the underlying representation |
| 209 | + /// `T`. |
| 210 | + /// |
| 211 | + /// This will move `T` onto the heap to create a single pointer to represent |
| 212 | + /// it which is then wrapped up in a component model resource. |
| 213 | + pub fn new(val: T) -> Resource<T> |
| 214 | + where |
| 215 | + T: RustResource, |
| 216 | + { |
| 217 | + let rep = Box::into_raw(Box::new(Some(val))) as usize; |
| 218 | + unsafe { |
| 219 | + let handle = T::new(rep); |
| 220 | + Resource::from_handle(handle) |
| 221 | + } |
| 222 | + } |
| 223 | + |
| 224 | + #[doc(hidden)] |
| 225 | + pub unsafe fn dtor(rep: usize) |
| 226 | + where |
| 227 | + T: RustResource, |
| 228 | + { |
| 229 | + let _ = Box::from_raw(rep as *mut RawRep<T>); |
| 230 | + } |
| 231 | + |
| 232 | + /// Takes back ownership of the object, dropping the resource handle. |
| 233 | + pub fn into_inner(resource: Self) -> T |
| 234 | + where |
| 235 | + T: RustResource, |
| 236 | + { |
| 237 | + unsafe { |
| 238 | + let rep = T::rep(resource.handle.load(Relaxed)); |
| 239 | + RawRep::take(&mut *(rep as *mut RawRep<T>)).unwrap() |
| 240 | + } |
| 241 | + } |
| 242 | + |
| 243 | + #[doc(hidden)] |
| 244 | + pub unsafe fn lift_borrow<'a>(rep: usize) -> &'a T |
| 245 | + where |
| 246 | + T: RustResource, |
| 247 | + { |
| 248 | + RawRep::as_ref(&*(rep as *const RawRep<T>)).unwrap() |
| 249 | + } |
| 250 | +} |
| 251 | + |
| 252 | +impl<T: RustResource> Deref for Resource<T> { |
| 253 | + type Target = T; |
| 254 | + |
| 255 | + fn deref(&self) -> &T { |
| 256 | + unsafe { |
| 257 | + let rep = T::rep(self.handle.load(Relaxed)); |
| 258 | + RawRep::as_ref(&*(rep as *const RawRep<T>)).unwrap() |
| 259 | + } |
| 260 | + } |
| 261 | +} |
| 262 | + |
| 263 | +impl<T: RustResource> DerefMut for Resource<T> { |
| 264 | + fn deref_mut(&mut self) -> &mut T { |
| 265 | + unsafe { |
| 266 | + let rep = T::rep(self.handle.load(Relaxed)); |
| 267 | + RawRep::as_mut(&mut *(rep as *mut RawRep<T>)).unwrap() |
| 268 | + } |
| 269 | + } |
| 270 | +} |
| 271 | + |
| 272 | +impl<T: WasmResource> fmt::Debug for Resource<T> { |
| 273 | + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 274 | + f.debug_struct("Resource") |
| 275 | + .field("handle", &self.handle) |
| 276 | + .finish() |
| 277 | + } |
| 278 | +} |
| 279 | + |
| 280 | +impl<T: WasmResource> Drop for Resource<T> { |
| 281 | + fn drop(&mut self) { |
| 282 | + unsafe { |
| 283 | + match self.handle.load(Relaxed) { |
| 284 | + // If this handle was "taken" then don't do anything in the |
| 285 | + // destructor. |
| 286 | + u32::MAX => {} |
| 287 | + |
| 288 | + // ... but otherwise do actually destroy it with the imported |
| 289 | + // component model intrinsic as defined through `T`. |
| 290 | + other => T::drop(other), |
| 291 | + } |
| 292 | + } |
| 293 | + } |
| 294 | +} |
0 commit comments