wasmtime/ref.rs
1#![allow(missing_docs)]
2
3use crate::AsContextMut;
4use std::any::Any;
5use wasmtime_runtime::VMExternRef;
6
7/// Represents an opaque reference to any data within WebAssembly.
8#[derive(Clone, Debug)]
9#[repr(transparent)]
10pub struct ExternRef {
11 pub(crate) inner: VMExternRef,
12}
13
14impl ExternRef {
15 /// Creates a new instance of `ExternRef` wrapping the given value.
16 pub fn new<T>(value: T) -> ExternRef
17 where
18 T: 'static + Any + Send + Sync,
19 {
20 let inner = VMExternRef::new(value);
21 ExternRef { inner }
22 }
23
24 /// Get the underlying data for this `ExternRef`.
25 pub fn data(&self) -> &dyn Any {
26 &*self.inner
27 }
28
29 /// Get the strong reference count for this `ExternRef`.
30 ///
31 /// Note that this loads the reference count with a `SeqCst` ordering to
32 /// synchronize with other threads.
33 pub fn strong_count(&self) -> usize {
34 self.inner.strong_count()
35 }
36
37 /// Does this `ExternRef` point to the same inner value as `other`?
38 ///
39 /// This is *only* pointer equality, and does *not* run any inner value's
40 /// `Eq` implementation.
41 pub fn ptr_eq(&self, other: &ExternRef) -> bool {
42 VMExternRef::eq(&self.inner, &other.inner)
43 }
44
45 /// Creates a new strongly-owned [`ExternRef`] from the raw value provided.
46 ///
47 /// This is intended to be used in conjunction with [`Func::new_unchecked`],
48 /// [`Func::call_unchecked`], and [`ValRaw`] with its `externref` field.
49 ///
50 /// This function assumes that `raw` is an externref value which is
51 /// currently rooted within the [`Store`].
52 ///
53 /// # Unsafety
54 ///
55 /// This function is particularly `unsafe` because `raw` not only must be a
56 /// valid externref value produced prior by `to_raw` but it must also be
57 /// correctly rooted within the store. When arguments are provided to a
58 /// callback with [`Func::new_unchecked`], for example, or returned via
59 /// [`Func::call_unchecked`], if a GC is performed within the store then
60 /// floating externref values are not rooted and will be GC'd, meaning that
61 /// this function will no longer be safe to call with the values cleaned up.
62 /// This function must be invoked *before* possible GC operations can happen
63 /// (such as calling wasm).
64 ///
65 /// When in doubt try to not use this. Instead use the safe Rust APIs of
66 /// [`TypedFunc`] and friends.
67 ///
68 /// [`Func::call_unchecked`]: crate::Func::call_unchecked
69 /// [`Func::new_unchecked`]: crate::Func::new_unchecked
70 /// [`Store`]: crate::Store
71 /// [`TypedFunc`]: crate::TypedFunc
72 /// [`ValRaw`]: crate::ValRaw
73 pub unsafe fn from_raw(raw: usize) -> Option<ExternRef> {
74 let raw = raw as *mut u8;
75 if raw.is_null() {
76 None
77 } else {
78 Some(ExternRef {
79 inner: VMExternRef::clone_from_raw(raw),
80 })
81 }
82 }
83
84 /// Converts this [`ExternRef`] to a raw value suitable to store within a
85 /// [`ValRaw`].
86 ///
87 /// # Unsafety
88 ///
89 /// Produces a raw value which is only safe to pass into a store if a GC
90 /// doesn't happen between when the value is produce and when it's passed
91 /// into the store.
92 ///
93 /// [`ValRaw`]: crate::ValRaw
94 pub unsafe fn to_raw(&self, mut store: impl AsContextMut) -> usize {
95 let externref_ptr = self.inner.as_raw();
96 store
97 .as_context_mut()
98 .0
99 .insert_vmexternref_without_gc(self.inner.clone());
100 externref_ptr as usize
101 }
102}
103
104impl std::fmt::Pointer for ExternRef {
105 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
106 std::fmt::Pointer::fmt(&self.inner, f)
107 }
108}