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, WasmtimeStoreContext, WasmtimeStoreContextMut, 4 }; 5 use anyhow::anyhow; 6 use std::mem::MaybeUninit; 7 use wasmtime::{Extern, Ref, RootScope, 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 r.map(|r| r.r.clone()) 37 .unwrap_or_else(|| Ref::null(table_ty.element().heap_type())) 38 } 39 40 #[unsafe(no_mangle)] 41 pub unsafe extern "C" fn wasm_table_new( 42 store: &mut wasm_store_t, 43 tt: &wasm_tabletype_t, 44 init: Option<&wasm_ref_t>, 45 ) -> Option<Box<wasm_table_t>> { 46 let tt = tt.ty().ty.clone(); 47 let init = option_wasm_ref_t_to_ref(init, &tt); 48 let table = Table::new(store.store.context_mut(), tt, init).ok()?; 49 Some(Box::new(wasm_table_t { 50 ext: wasm_extern_t { 51 store: store.store.clone(), 52 which: table.into(), 53 }, 54 })) 55 } 56 57 #[unsafe(no_mangle)] 58 pub unsafe extern "C" fn wasm_table_type(t: &wasm_table_t) -> Box<wasm_tabletype_t> { 59 let table = t.table(); 60 let store = t.ext.store.context(); 61 Box::new(wasm_tabletype_t::new(table.ty(&store))) 62 } 63 64 #[unsafe(no_mangle)] 65 pub unsafe extern "C" fn wasm_table_get( 66 t: &mut wasm_table_t, 67 index: wasm_table_size_t, 68 ) -> Option<Box<wasm_ref_t>> { 69 let table = t.table(); 70 let r = table.get(t.ext.store.context_mut(), u64::from(index))?; 71 wasm_ref_t::new(r) 72 } 73 74 #[unsafe(no_mangle)] 75 pub unsafe extern "C" fn wasm_table_set( 76 t: &mut wasm_table_t, 77 index: wasm_table_size_t, 78 r: Option<&wasm_ref_t>, 79 ) -> bool { 80 let table = t.table(); 81 let val = option_wasm_ref_t_to_ref(r, &table.ty(t.ext.store.context())); 82 table 83 .set(t.ext.store.context_mut(), u64::from(index), val) 84 .is_ok() 85 } 86 87 #[unsafe(no_mangle)] 88 pub unsafe extern "C" fn wasm_table_size(t: &wasm_table_t) -> wasm_table_size_t { 89 let table = t.table(); 90 let store = t.ext.store.context(); 91 u32::try_from(table.size(&store)).unwrap() 92 } 93 94 #[unsafe(no_mangle)] 95 pub unsafe extern "C" fn wasm_table_grow( 96 t: &mut wasm_table_t, 97 delta: wasm_table_size_t, 98 init: Option<&wasm_ref_t>, 99 ) -> bool { 100 let table = t.table(); 101 let init = option_wasm_ref_t_to_ref(init, &table.ty(t.ext.store.context())); 102 table 103 .grow(t.ext.store.context_mut(), u64::from(delta), init) 104 .is_ok() 105 } 106 107 #[unsafe(no_mangle)] 108 pub extern "C" fn wasm_table_as_extern(t: &mut wasm_table_t) -> &mut wasm_extern_t { 109 &mut t.ext 110 } 111 112 #[unsafe(no_mangle)] 113 pub extern "C" fn wasm_table_as_extern_const(t: &wasm_table_t) -> &wasm_extern_t { 114 &t.ext 115 } 116 117 #[unsafe(no_mangle)] 118 pub unsafe extern "C" fn wasmtime_table_new( 119 mut store: WasmtimeStoreContextMut<'_>, 120 tt: &wasm_tabletype_t, 121 init: &wasmtime_val_t, 122 out: &mut Table, 123 ) -> Option<Box<wasmtime_error_t>> { 124 let mut scope = RootScope::new(&mut store); 125 handle_result( 126 init.to_val(&mut scope) 127 .ref_() 128 .ok_or_else(|| anyhow!("wasmtime_table_new init value is not a reference")) 129 .and_then(|init| Table::new(scope, tt.ty().ty.clone(), init)), 130 |table| *out = table, 131 ) 132 } 133 134 #[unsafe(no_mangle)] 135 pub unsafe extern "C" fn wasmtime_table_type( 136 store: WasmtimeStoreContext<'_>, 137 table: &Table, 138 ) -> Box<wasm_tabletype_t> { 139 Box::new(wasm_tabletype_t::new(table.ty(store))) 140 } 141 142 #[unsafe(no_mangle)] 143 pub extern "C" fn wasmtime_table_get( 144 store: WasmtimeStoreContextMut<'_>, 145 table: &Table, 146 index: u64, 147 ret: &mut MaybeUninit<wasmtime_val_t>, 148 ) -> bool { 149 let mut scope = RootScope::new(store); 150 match table.get(&mut scope, index) { 151 Some(r) => { 152 crate::initialize(ret, wasmtime_val_t::from_val(&mut scope, r.into())); 153 true 154 } 155 None => false, 156 } 157 } 158 159 #[unsafe(no_mangle)] 160 pub unsafe extern "C" fn wasmtime_table_set( 161 mut store: WasmtimeStoreContextMut<'_>, 162 table: &Table, 163 index: u64, 164 val: &wasmtime_val_t, 165 ) -> Option<Box<wasmtime_error_t>> { 166 let mut scope = RootScope::new(&mut store); 167 handle_result( 168 val.to_val(&mut scope) 169 .ref_() 170 .ok_or_else(|| anyhow!("wasmtime_table_set value is not a reference")) 171 .and_then(|val| table.set(scope, index, val)), 172 |()| {}, 173 ) 174 } 175 176 #[unsafe(no_mangle)] 177 pub extern "C" fn wasmtime_table_size(store: WasmtimeStoreContext<'_>, table: &Table) -> u64 { 178 table.size(store) 179 } 180 181 #[unsafe(no_mangle)] 182 pub unsafe extern "C" fn wasmtime_table_grow( 183 mut store: WasmtimeStoreContextMut<'_>, 184 table: &Table, 185 delta: u64, 186 val: &wasmtime_val_t, 187 prev_size: &mut u64, 188 ) -> Option<Box<wasmtime_error_t>> { 189 let mut scope = RootScope::new(&mut store); 190 handle_result( 191 val.to_val(&mut scope) 192 .ref_() 193 .ok_or_else(|| anyhow!("wasmtime_table_grow value is not a reference")) 194 .and_then(|val| table.grow(scope, delta, val)), 195 |prev| *prev_size = prev, 196 ) 197 } 198