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