extism_runtime/
function.rs

1use crate::{Error, Internal};
2
3/// A list of all possible value types in WebAssembly.
4#[derive(Debug, Clone, Hash, Eq, PartialEq)]
5#[repr(C)]
6pub enum ValType {
7    // NB: the ordering here is intended to match the ordering in
8    // `wasmtime_types::WasmType` to help improve codegen when converting.
9    /// Signed 32 bit integer.
10    I32,
11    /// Signed 64 bit integer.
12    I64,
13    /// Floating point 32 bit integer.
14    F32,
15    /// Floating point 64 bit integer.
16    F64,
17    /// A 128 bit number.
18    V128,
19    /// A reference to a Wasm function.
20    FuncRef,
21    /// A reference to opaque data in the Wasm instance.
22    ExternRef,
23}
24
25impl From<wasmtime::ValType> for ValType {
26    fn from(value: wasmtime::ValType) -> Self {
27        use wasmtime::ValType::*;
28        match value {
29            I32 => ValType::I32,
30            I64 => ValType::I64,
31            F32 => ValType::F32,
32            F64 => ValType::F64,
33            V128 => ValType::V128,
34            FuncRef => ValType::FuncRef,
35            ExternRef => ValType::ExternRef,
36        }
37    }
38}
39
40impl From<ValType> for wasmtime::ValType {
41    fn from(value: ValType) -> Self {
42        use ValType::*;
43        match value {
44            I32 => wasmtime::ValType::I32,
45            I64 => wasmtime::ValType::I64,
46            F32 => wasmtime::ValType::F32,
47            F64 => wasmtime::ValType::F64,
48            V128 => wasmtime::ValType::V128,
49            FuncRef => wasmtime::ValType::FuncRef,
50            ExternRef => wasmtime::ValType::ExternRef,
51        }
52    }
53}
54
55pub type Val = wasmtime::Val;
56
57pub struct UserData {
58    ptr: *mut std::ffi::c_void,
59    free: Option<extern "C" fn(_: *mut std::ffi::c_void)>,
60    is_any: bool,
61}
62
63extern "C" fn free_any(ptr: *mut std::ffi::c_void) {
64    let ptr = ptr as *mut dyn std::any::Any;
65    unsafe { drop(Box::from_raw(ptr)) }
66}
67
68impl UserData {
69    pub fn new_pointer(
70        ptr: *mut std::ffi::c_void,
71        free: Option<extern "C" fn(_: *mut std::ffi::c_void)>,
72    ) -> Self {
73        UserData {
74            ptr,
75            free,
76            is_any: false,
77        }
78    }
79
80    pub fn new<T: std::any::Any>(x: T) -> Self {
81        let ptr = Box::into_raw(Box::new(x)) as *mut _;
82        UserData {
83            ptr,
84            free: Some(free_any),
85            is_any: true,
86        }
87    }
88
89    pub fn is_null(&self) -> bool {
90        self.ptr.is_null()
91    }
92
93    pub fn as_ptr(&self) -> *mut std::ffi::c_void {
94        self.ptr
95    }
96
97    pub(crate) fn make_copy(&self) -> Self {
98        UserData {
99            ptr: self.ptr,
100            free: None,
101            is_any: self.is_any,
102        }
103    }
104
105    pub fn any(&self) -> Option<&dyn std::any::Any> {
106        if !self.is_any || self.is_null() {
107            return None;
108        }
109
110        unsafe { Some(&*self.ptr) }
111    }
112
113    pub fn any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
114        if !self.is_any || self.is_null() {
115            return None;
116        }
117
118        unsafe { Some(&mut *self.ptr) }
119    }
120}
121
122impl Default for UserData {
123    fn default() -> Self {
124        UserData {
125            ptr: std::ptr::null_mut(),
126            free: None,
127            is_any: false,
128        }
129    }
130}
131
132impl Drop for UserData {
133    fn drop(&mut self) {
134        if self.ptr.is_null() {
135            return;
136        }
137
138        if let Some(free) = self.free {
139            free(self.ptr);
140        }
141
142        self.ptr = std::ptr::null_mut();
143    }
144}
145
146unsafe impl Send for UserData {}
147unsafe impl Sync for UserData {}
148
149type FunctionInner = dyn Fn(wasmtime::Caller<Internal>, &[wasmtime::Val], &mut [wasmtime::Val]) -> Result<(), Error>
150    + Sync
151    + Send;
152
153#[derive(Clone)]
154pub struct Function {
155    pub(crate) name: String,
156    pub(crate) ty: wasmtime::FuncType,
157    pub(crate) f: std::sync::Arc<FunctionInner>,
158    pub(crate) namespace: Option<String>,
159    pub(crate) _user_data: std::sync::Arc<UserData>,
160}
161
162impl Function {
163    pub fn new<F>(
164        name: impl Into<String>,
165        args: impl IntoIterator<Item = ValType>,
166        returns: impl IntoIterator<Item = ValType>,
167        user_data: Option<UserData>,
168        f: F,
169    ) -> Function
170    where
171        F: 'static
172            + Fn(&mut Internal, &[Val], &mut [Val], UserData) -> Result<(), Error>
173            + Sync
174            + Send,
175    {
176        let user_data = user_data.unwrap_or_default();
177        let data = user_data.make_copy();
178        Function {
179            name: name.into(),
180            ty: wasmtime::FuncType::new(
181                args.into_iter().map(wasmtime::ValType::from),
182                returns.into_iter().map(wasmtime::ValType::from),
183            ),
184            f: std::sync::Arc::new(move |mut caller, inp, outp| {
185                f(caller.data_mut(), inp, outp, data.make_copy())
186            }),
187            namespace: None,
188            _user_data: std::sync::Arc::new(user_data),
189        }
190    }
191
192    pub fn name(&self) -> &str {
193        &self.name
194    }
195
196    pub fn namespace(&self) -> Option<&str> {
197        self.namespace.as_deref()
198    }
199
200    pub fn set_namespace(&mut self, namespace: impl Into<String>) {
201        self.namespace = Some(namespace.into());
202    }
203
204    pub fn with_namespace(mut self, namespace: impl Into<String>) -> Self {
205        self.set_namespace(namespace);
206        self
207    }
208
209    pub fn ty(&self) -> &wasmtime::FuncType {
210        &self.ty
211    }
212}