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}