wasmer_c_api/wasm_c_api/externals/
table.rs

1use crate::error::update_last_error;
2
3use super::super::store::{StoreRef, wasm_store_t};
4use super::super::types::{wasm_ref_t, wasm_table_size_t, wasm_tabletype_t};
5use super::wasm_extern_t;
6use wasmer_api::{Extern, Table, Type, Value};
7
8#[allow(non_camel_case_types)]
9#[repr(C)]
10#[derive(Clone)]
11pub struct wasm_table_t {
12    pub(crate) extern_: wasm_extern_t,
13}
14
15impl wasm_table_t {
16    pub(crate) fn try_from(e: &wasm_extern_t) -> Option<&wasm_table_t> {
17        match &e.inner {
18            Extern::Table(_) => Some(unsafe { &*(e as *const _ as *const _) }),
19            _ => None,
20        }
21    }
22}
23
24/// Builds the [`Value`] to store into a table slot from a caller-provided
25/// reference and the table's element type. A null `init` becomes the null
26/// reference of the appropriate kind.
27fn init_value(init: *const wasm_ref_t, element_ty: Type) -> Value {
28    if init.is_null() {
29        match element_ty {
30            Type::FuncRef => Value::FuncRef(None),
31            _ => Value::ExternRef(None),
32        }
33    } else {
34        // The boxed `wasm_ref_t` carries the authoritative reference value.
35        unsafe { &*init }.inner.clone()
36    }
37}
38
39#[unsafe(no_mangle)]
40pub unsafe extern "C" fn wasm_table_new(
41    store: Option<&mut wasm_store_t>,
42    table_type: Option<&wasm_tabletype_t>,
43    init: *const wasm_ref_t,
44) -> Option<Box<wasm_table_t>> {
45    let store = store?;
46    let table_type = table_type?;
47    let table_type = table_type.inner()._table_type;
48    let init_val = init_value(init, table_type.ty);
49
50    let table = {
51        let mut store_mut = unsafe { store.inner.store_mut() };
52        c_try!(Table::new(&mut store_mut, table_type, init_val))
53    };
54
55    Some(Box::new(wasm_table_t {
56        extern_: wasm_extern_t::new(store.inner.clone(), table.into()),
57    }))
58}
59
60#[unsafe(no_mangle)]
61pub unsafe extern "C" fn wasm_table_delete(_table: Option<Box<wasm_table_t>>) {}
62
63#[unsafe(no_mangle)]
64pub unsafe extern "C" fn wasm_table_copy(
65    table: Option<&wasm_table_t>,
66) -> Option<Box<wasm_table_t>> {
67    table.cloned().map(Box::new)
68}
69
70#[unsafe(no_mangle)]
71pub unsafe extern "C" fn wasm_table_size(table: Option<&wasm_table_t>) -> usize {
72    let Some(table) = table else {
73        update_last_error("table pointer is null");
74        return 0;
75    };
76    let store_ref = unsafe { table.extern_.store.store() };
77    table.extern_.table().size(&store_ref) as _
78}
79
80#[unsafe(no_mangle)]
81pub unsafe extern "C" fn wasm_table_type(
82    table: Option<&wasm_table_t>,
83) -> Option<Box<wasm_tabletype_t>> {
84    let Some(table) = table else {
85        update_last_error("table pointer is null");
86        return None;
87    };
88    let store_ref = unsafe { table.extern_.store.store() };
89    Some(Box::new(wasm_tabletype_t::new(
90        table.extern_.table().ty(&store_ref),
91    )))
92}
93
94#[unsafe(no_mangle)]
95pub unsafe extern "C" fn wasm_table_same(
96    wasm_table1: &wasm_table_t,
97    wasm_table2: &wasm_table_t,
98) -> bool {
99    wasm_table1.extern_.table() == wasm_table2.extern_.table()
100}
101
102#[unsafe(no_mangle)]
103pub unsafe extern "C" fn wasm_table_get(
104    table: Option<&wasm_table_t>,
105    index: wasm_table_size_t,
106) -> Option<Box<wasm_ref_t>> {
107    let Some(table) = table else {
108        update_last_error("table pointer is null");
109        return None;
110    };
111    let table_obj = table.extern_.table();
112    let mut store: StoreRef = table.extern_.store.clone();
113    // `Table::get` returns `None` only for an out-of-bounds index; an in-bounds
114    // null element is `Some(ExternRef(None))`, which boxes to a null
115    // `wasm_ref_t*` below without registering an error.
116    let value = {
117        let mut store_mut = unsafe { store.store_mut() };
118        match table_obj.get(&mut store_mut, index) {
119            Some(value) => value,
120            None => {
121                update_last_error("table index out of bounds");
122                return None;
123            }
124        }
125    };
126    wasm_ref_t::new(table.extern_.store.clone(), value)
127}
128
129#[unsafe(no_mangle)]
130pub unsafe extern "C" fn wasm_table_set(
131    table: Option<&mut wasm_table_t>,
132    index: wasm_table_size_t,
133    r: *mut wasm_ref_t,
134) -> bool {
135    let Some(table) = table else {
136        update_last_error("table pointer is null");
137        return false;
138    };
139    let table_obj = table.extern_.table();
140    let mut store: StoreRef = table.extern_.store.clone();
141    let mut store_mut = unsafe { store.store_mut() };
142    let element_ty = table_obj.ty(&store_mut).ty;
143    let value = init_value(r, element_ty);
144    match table_obj.set(&mut store_mut, index, value) {
145        Ok(()) => true,
146        Err(e) => {
147            update_last_error(e);
148            false
149        }
150    }
151}
152
153#[unsafe(no_mangle)]
154pub unsafe extern "C" fn wasm_table_grow(
155    table: &mut wasm_table_t,
156    delta: wasm_table_size_t,
157    init: *mut wasm_ref_t,
158) -> bool {
159    let table_obj = table.extern_.table();
160    let mut store: StoreRef = table.extern_.store.clone();
161    let mut store_mut = unsafe { store.store_mut() };
162    let element_ty = table_obj.ty(&store_mut).ty;
163    let init_val = init_value(init, element_ty);
164    match table_obj.grow(&mut store_mut, delta, init_val) {
165        Ok(_) => true,
166        Err(e) => {
167            update_last_error(e);
168            false
169        }
170    }
171}