xref: /wasmtime-44.0.1/crates/c-api/src/table.rs (revision bd2ea901)
1 use crate::{
2     handle_result, wasm_extern_t, wasm_ref_t, wasm_store_t, wasm_tabletype_t, wasmtime_error_t,
3     wasmtime_val_t, CStoreContext, CStoreContextMut,
4 };
5 use anyhow::anyhow;
6 use std::mem::MaybeUninit;
7 use wasmtime::{Extern, HeapType, Ref, Table, TableType};
8 
9 #[derive(Clone)]
10 #[repr(transparent)]
11 pub struct wasm_table_t {
12     ext: wasm_extern_t,
13 }
14 
15 wasmtime_c_api_macros::declare_ref!(wasm_table_t);
16 
17 pub type wasm_table_size_t = u32;
18 
19 impl wasm_table_t {
20     pub(crate) fn try_from(e: &wasm_extern_t) -> Option<&wasm_table_t> {
21         match &e.which {
22             Extern::Table(_) => Some(unsafe { &*(e as *const _ as *const _) }),
23             _ => None,
24         }
25     }
26 
27     fn table(&self) -> Table {
28         match self.ext.which {
29             Extern::Table(t) => t,
30             _ => unsafe { std::hint::unreachable_unchecked() },
31         }
32     }
33 }
34 
35 fn option_wasm_ref_t_to_ref(r: Option<&wasm_ref_t>, table_ty: &TableType) -> Ref {
36     match (r.map(|r| r.r.clone()), table_ty.element().heap_type()) {
37         (None, HeapType::NoFunc | HeapType::Func | HeapType::Concrete(_)) => Ref::Func(None),
38         (None, HeapType::Extern) => Ref::Extern(None),
39         (Some(r), _) => r,
40     }
41 }
42 
43 #[no_mangle]
44 pub unsafe extern "C" fn wasm_table_new(
45     store: &mut wasm_store_t,
46     tt: &wasm_tabletype_t,
47     init: Option<&wasm_ref_t>,
48 ) -> Option<Box<wasm_table_t>> {
49     let tt = tt.ty().ty.clone();
50     let init = option_wasm_ref_t_to_ref(init, &tt);
51     let table = Table::new(store.store.context_mut(), tt, init).ok()?;
52     Some(Box::new(wasm_table_t {
53         ext: wasm_extern_t {
54             store: store.store.clone(),
55             which: table.into(),
56         },
57     }))
58 }
59 
60 #[no_mangle]
61 pub unsafe extern "C" fn wasm_table_type(t: &wasm_table_t) -> Box<wasm_tabletype_t> {
62     let table = t.table();
63     let store = t.ext.store.context();
64     Box::new(wasm_tabletype_t::new(table.ty(&store)))
65 }
66 
67 #[no_mangle]
68 pub unsafe extern "C" fn wasm_table_get(
69     t: &mut wasm_table_t,
70     index: wasm_table_size_t,
71 ) -> Option<Box<wasm_ref_t>> {
72     let table = t.table();
73     let r = table.get(t.ext.store.context_mut(), index)?;
74     wasm_ref_t::new(r)
75 }
76 
77 #[no_mangle]
78 pub unsafe extern "C" fn wasm_table_set(
79     t: &mut wasm_table_t,
80     index: wasm_table_size_t,
81     r: Option<&wasm_ref_t>,
82 ) -> bool {
83     let table = t.table();
84     let val = option_wasm_ref_t_to_ref(r, &table.ty(t.ext.store.context()));
85     table.set(t.ext.store.context_mut(), index, val).is_ok()
86 }
87 
88 #[no_mangle]
89 pub unsafe extern "C" fn wasm_table_size(t: &wasm_table_t) -> wasm_table_size_t {
90     let table = t.table();
91     let store = t.ext.store.context();
92     table.size(&store)
93 }
94 
95 #[no_mangle]
96 pub unsafe extern "C" fn wasm_table_grow(
97     t: &mut wasm_table_t,
98     delta: wasm_table_size_t,
99     init: Option<&wasm_ref_t>,
100 ) -> bool {
101     let table = t.table();
102     let init = option_wasm_ref_t_to_ref(init, &table.ty(t.ext.store.context()));
103     table.grow(t.ext.store.context_mut(), delta, init).is_ok()
104 }
105 
106 #[no_mangle]
107 pub extern "C" fn wasm_table_as_extern(t: &mut wasm_table_t) -> &mut wasm_extern_t {
108     &mut t.ext
109 }
110 
111 #[no_mangle]
112 pub extern "C" fn wasm_table_as_extern_const(t: &wasm_table_t) -> &wasm_extern_t {
113     &t.ext
114 }
115 
116 #[no_mangle]
117 pub unsafe extern "C" fn wasmtime_table_new(
118     mut store: CStoreContextMut<'_>,
119     tt: &wasm_tabletype_t,
120     init: &wasmtime_val_t,
121     out: &mut Table,
122 ) -> Option<Box<wasmtime_error_t>> {
123     handle_result(
124         init.to_val(&mut store)
125             .ref_()
126             .ok_or_else(|| anyhow!("wasmtime_table_new init value is not a reference"))
127             .and_then(|init| Table::new(store, tt.ty().ty.clone(), init)),
128         |table| *out = table,
129     )
130 }
131 
132 #[no_mangle]
133 pub unsafe extern "C" fn wasmtime_table_type(
134     store: CStoreContext<'_>,
135     table: &Table,
136 ) -> Box<wasm_tabletype_t> {
137     Box::new(wasm_tabletype_t::new(table.ty(store)))
138 }
139 
140 #[no_mangle]
141 pub extern "C" fn wasmtime_table_get(
142     mut store: CStoreContextMut<'_>,
143     table: &Table,
144     index: u32,
145     ret: &mut MaybeUninit<wasmtime_val_t>,
146 ) -> bool {
147     match table.get(&mut store, index) {
148         Some(r) => {
149             crate::initialize(ret, wasmtime_val_t::from_val(store, r.into()));
150             true
151         }
152         None => false,
153     }
154 }
155 
156 #[no_mangle]
157 pub unsafe extern "C" fn wasmtime_table_set(
158     mut store: CStoreContextMut<'_>,
159     table: &Table,
160     index: u32,
161     val: &wasmtime_val_t,
162 ) -> Option<Box<wasmtime_error_t>> {
163     handle_result(
164         val.to_val(&mut store)
165             .ref_()
166             .ok_or_else(|| anyhow!("wasmtime_table_set value is not a reference"))
167             .and_then(|val| table.set(store, index, val)),
168         |()| {},
169     )
170 }
171 
172 #[no_mangle]
173 pub extern "C" fn wasmtime_table_size(store: CStoreContext<'_>, table: &Table) -> u32 {
174     table.size(store)
175 }
176 
177 #[no_mangle]
178 pub unsafe extern "C" fn wasmtime_table_grow(
179     mut store: CStoreContextMut<'_>,
180     table: &Table,
181     delta: u32,
182     val: &wasmtime_val_t,
183     prev_size: &mut u32,
184 ) -> Option<Box<wasmtime_error_t>> {
185     handle_result(
186         val.to_val(&mut store)
187             .ref_()
188             .ok_or_else(|| anyhow!("wasmtime_table_grow value is not a reference"))
189             .and_then(|val| table.grow(store, delta, val)),
190         |prev| *prev_size = prev,
191     )
192 }
193