wasmi_c_api/
store.rs

1use crate::{wasm_engine_t, wasmi_error_t, ForeignData};
2use alloc::{boxed::Box, sync::Arc};
3use core::{cell::UnsafeCell, ffi};
4use wasmi::{AsContext, AsContextMut, Store, StoreContext, StoreContextMut};
5
6/// This representation of a `Store` is used to implement the `wasm.h` API (and
7/// *not* the `wasmi.h` API!)
8///
9/// This is stored alongside `Func` and such for `wasm.h` so each object is
10/// independently owned. The usage of `Arc` here is mostly to just get it to be
11/// safe to drop across multiple threads, but otherwise acquiring the `context`
12/// values from this struct is considered unsafe due to it being unknown how the
13/// aliasing is working on the C side of things.
14///
15/// The aliasing requirements are documented in the C API `wasm.h` itself (at
16/// least Wasmi's implementation).
17#[derive(Clone)]
18pub struct WasmStoreRef {
19    inner: Arc<UnsafeCell<Store<()>>>,
20}
21
22impl WasmStoreRef {
23    /// Returns shared access to the store context of the [`WasmStoreRef`].
24    ///
25    /// Wraps [`wasmi::AsContext`].
26    ///
27    /// # Safety
28    ///
29    /// It is the callers responsibility to provide a valid `self`.
30    pub unsafe fn context(&self) -> StoreContext<'_, ()> {
31        (*self.inner.get()).as_context()
32    }
33
34    /// Returns mutable access to the store context of the [`WasmStoreRef`].
35    ///
36    /// Wraps [`wasmi::AsContextMut`].
37    ///
38    /// # Safety
39    ///
40    /// It is the callers responsibility to provide a valid `self`.
41    pub unsafe fn context_mut(&mut self) -> StoreContextMut<'_, ()> {
42        (*self.inner.get()).as_context_mut()
43    }
44}
45
46/// The Wasm store.
47///
48/// The returned [`wasm_engine_t`] must be freed using [`wasm_store_delete`].
49///
50/// Wraps [`wasmi::Store<()>`](wasmi::Store).
51#[repr(C)]
52#[derive(Clone)]
53pub struct wasm_store_t {
54    pub(crate) inner: WasmStoreRef,
55}
56
57wasmi_c_api_macros::declare_own!(wasm_store_t);
58
59/// Creates a new [`Store<()>`](wasmi::Store) for the given `engine`.
60///
61/// The returned [`wasm_store_t`] must be freed using [`wasm_store_delete`].
62///
63/// Wraps [`<wasmi::Store<()>>::new`](wasmi::Store::new).
64#[cfg_attr(not(feature = "prefix-symbols"), no_mangle)]
65#[allow(clippy::arc_with_non_send_sync)]
66#[cfg_attr(feature = "prefix-symbols", wasmi_c_api_macros::prefix_symbol)]
67pub extern "C" fn wasm_store_new(engine: &wasm_engine_t) -> Box<wasm_store_t> {
68    let engine = &engine.inner;
69    let store = Store::new(engine, ());
70    Box::new(wasm_store_t {
71        inner: WasmStoreRef {
72            inner: Arc::new(UnsafeCell::new(store)),
73        },
74    })
75}
76
77/// The Wasm store with foreign data and optional WASI support.
78///
79/// The returned [`wasm_engine_t`] must be freed using [`wasm_store_delete`].
80///
81/// Wraps [`wasmi::Store<WasmiStoreData>`](wasmi::Store).
82#[repr(C)]
83pub struct wasmi_store_t {
84    pub(crate) store: Store<WasmiStoreData>,
85}
86
87wasmi_c_api_macros::declare_own!(wasmi_store_t);
88
89/// Extensional data stored by [`wasmi_store_t`] to handle foreign data and optional WASI support.
90pub struct WasmiStoreData {
91    foreign: ForeignData,
92}
93
94/// Creates a new [`Store<()>`](wasmi::Store) for the given `engine`.
95///
96/// - This takes a foreign `data` with an associated `finalizer`.
97/// - The returned [`wasm_store_t`] must be freed using [`wasm_store_delete`].
98///
99/// Wraps [`<wasmi::Store<()>>::new`](wasmi::Store::new).
100#[no_mangle]
101pub extern "C" fn wasmi_store_new(
102    engine: &wasm_engine_t,
103    data: *mut ffi::c_void,
104    finalizer: Option<extern "C" fn(*mut ffi::c_void)>,
105) -> Box<wasmi_store_t> {
106    Box::new(wasmi_store_t {
107        store: Store::new(
108            &engine.inner,
109            WasmiStoreData {
110                foreign: ForeignData { data, finalizer },
111            },
112        ),
113    })
114}
115
116/// Returns mutable access to the store context of the [`wasmi_store_t`].
117///
118/// Wraps [`wasmi::AsContext`].
119///
120/// # Safety
121///
122/// It is the callers responsibility to provide a valid `self`.
123#[no_mangle]
124pub extern "C" fn wasmi_store_context(
125    store: &mut wasmi_store_t,
126) -> StoreContextMut<'_, WasmiStoreData> {
127    store.store.as_context_mut()
128}
129
130/// Returns a pointer to the foreign data of the Wasmi store context.
131#[no_mangle]
132pub extern "C" fn wasmi_context_get_data(
133    store: StoreContext<'_, WasmiStoreData>,
134) -> *mut ffi::c_void {
135    store.data().foreign.data
136}
137
138/// Sets the foreign data of the Wasmi store context.
139#[no_mangle]
140pub extern "C" fn wasmi_context_set_data(
141    mut store: StoreContextMut<'_, WasmiStoreData>,
142    data: *mut ffi::c_void,
143) {
144    store.data_mut().foreign.data = data;
145}
146
147/// Returns the current fuel of the Wasmi store context in `fuel`.
148///
149/// Wraps [`Store::get_fuel`].
150///
151/// # Errors
152///
153/// If [`Store::get_fuel`] errors.
154#[no_mangle]
155pub extern "C" fn wasmi_context_get_fuel(
156    store: StoreContext<'_, WasmiStoreData>,
157    fuel: &mut u64,
158) -> Option<Box<wasmi_error_t>> {
159    crate::handle_result(store.get_fuel(), |amt| {
160        *fuel = amt;
161    })
162}
163
164/// Sets the current fuel of the Wasmi store context to `fuel`.
165///
166/// Wraps [`Store::set_fuel`].
167///
168/// # Errors
169///
170/// If [`Store::set_fuel`] errors.
171#[no_mangle]
172pub extern "C" fn wasmi_context_set_fuel(
173    mut store: StoreContextMut<'_, WasmiStoreData>,
174    fuel: u64,
175) -> Option<Box<wasmi_error_t>> {
176    crate::handle_result(store.set_fuel(fuel), |()| {})
177}