From a104d08c048a695603ce4fe8cef0fbc86b609ea0 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Tue, 29 Oct 2019 14:55:14 -0700 Subject: [PATCH] Update ImportObject C API to use iterators --- lib/runtime-c-api/src/import/mod.rs | 197 ++++++++++++------ .../tests/test-wasi-import-object | Bin 19508 -> 15612 bytes .../tests/test-wasi-import-object.c | 34 ++- lib/runtime-c-api/wasmer.h | 56 +++-- lib/runtime-c-api/wasmer.hh | 44 ++-- 5 files changed, 208 insertions(+), 123 deletions(-) diff --git a/lib/runtime-c-api/src/import/mod.rs b/lib/runtime-c-api/src/import/mod.rs index ad0470af6..a38645dd1 100644 --- a/lib/runtime-c-api/src/import/mod.rs +++ b/lib/runtime-c-api/src/import/mod.rs @@ -13,7 +13,7 @@ use std::{convert::TryFrom, ffi::c_void, ptr, slice, sync::Arc}; use wasmer_runtime::{Global, Memory, Module, Table}; use wasmer_runtime_core::{ export::{Context, Export, FuncPointer}, - import::ImportObject, + import::{ImportObject, ImportObjectIterator}, module::ImportName, types::{FuncSig, Type}, }; @@ -41,6 +41,10 @@ pub struct wasmer_import_descriptor_t; #[derive(Clone)] pub struct wasmer_import_descriptors_t; +#[repr(C)] +#[derive(Clone)] +pub struct wasmer_import_object_iter_t; + /// Creates a new empty import object. /// See also `wasmer_import_object_append` #[allow(clippy::cast_ptr_alignment)] @@ -58,12 +62,11 @@ mod wasi; pub use self::wasi::*; /// Gets an entry from an ImportObject at the name and namespace. -/// Stores an immutable reference to `name` and `namespace` in `import`. +/// Stores `name`, `namespace`, and `import_export_value` in `import`. +/// Thus these must remain valid for the lifetime of `import`. /// /// The caller owns all data involved. -/// `import_export_value` will be written to based on `tag`, `import_export_value` must be -/// initialized to point to the type specified by `tag`. Failure to do so may result -/// in data corruption or undefined behavior. +/// `import_export_value` will be written to based on `tag`. #[no_mangle] pub unsafe extern "C" fn wasmer_import_object_get_import( import_object: *const wasmer_import_object_t, @@ -169,95 +172,157 @@ pub unsafe extern "C" fn wasmer_import_object_get_import( } } +/// private wrapper data type used for casting +#[repr(C)] +struct WasmerImportObjectIterator( + std::iter::Peekable::Item>>>, +); + +/// Create an iterator over the functions in the import object. +/// Get the next import with `wasmer_import_object_iter_next` +/// Free the iterator with `wasmer_import_object_iter_destroy` #[no_mangle] -/// Get the number of functions that an import object contains. -/// The result of this is useful as an argument to `wasmer_import_object_get_functions`. -/// This function returns -1 on error. -pub unsafe extern "C" fn wasmer_import_object_get_num_functions( +pub unsafe extern "C" fn wasmer_import_object_iterate_functions( import_object: *const wasmer_import_object_t, -) -> i32 { +) -> *mut wasmer_import_object_iter_t { if import_object.is_null() { update_last_error(CApiError { msg: "import_object must not be null".to_owned(), }); - return -1; + return std::ptr::null_mut(); } let import_object: &ImportObject = &*(import_object as *const ImportObject); - import_object - .clone_ref() - .into_iter() - .filter(|(_, _, e)| { - if let Export::Function { .. } = e { - true - } else { - false - } - }) - .count() as i32 + let iter_inner = Box::new(import_object.clone_ref().into_iter().filter(|(_, _, e)| { + if let Export::Function { .. } = e { + true + } else { + false + } + })) as Box::Item>>; + let iterator = Box::new(WasmerImportObjectIterator(iter_inner.peekable())); + + Box::into_raw(iterator) as *mut wasmer_import_object_iter_t } +/// Writes the next value to `import`. `WASMER_ERROR` is returned if there +/// was an error or there's nothing left to return. +/// +/// To free the memory allocated here, pass the import to `wasmer_import_object_imports_destroy`. +/// To check if the iterator is done, use `wasmer_import_object_iter_at_end`. #[no_mangle] -/// Call `wasmer_import_object_imports_destroy` to free the memory allocated by this function. -/// This function return -1 on error. -pub unsafe extern "C" fn wasmer_import_object_get_functions( - import_object: *const wasmer_import_object_t, - imports: *mut wasmer_import_t, - imports_len: u32, -) -> i32 { - if import_object.is_null() || imports.is_null() { +pub unsafe extern "C" fn wasmer_import_object_iter_next( + import_object_iter: *mut wasmer_import_object_iter_t, + import: *mut wasmer_import_t, +) -> wasmer_result_t { + if import_object_iter.is_null() || import.is_null() { update_last_error(CApiError { - msg: "import_object and imports must not be null".to_owned(), + msg: "import_object_iter and import must not be null".to_owned(), }); - return -1; + return wasmer_result_t::WASMER_ERROR; } - let import_object: &ImportObject = &*(import_object as *const ImportObject); - let mut i = 0; - for (namespace, name, export) in import_object.clone_ref().into_iter() { - if i + 1 > imports_len { - return i as i32; - } + let iter = &mut *(import_object_iter as *mut WasmerImportObjectIterator); + let out = &mut *import; + // TODO: the copying here can be optimized away, we just need to use a different type of + // iterator internally + if let Some((namespace, name, export)) = iter.0.next() { + let ns = { + let mut n = namespace.clone(); + n.shrink_to_fit(); + n.into_bytes() + }; + let ns_bytes = wasmer_byte_array { + bytes: ns.as_ptr(), + bytes_len: ns.len() as u32, + }; + + let name = { + let mut n = name.clone(); + n.shrink_to_fit(); + n.into_bytes() + }; + let name_bytes = wasmer_byte_array { + bytes: name.as_ptr(), + bytes_len: name.len() as u32, + }; + + out.module_name = ns_bytes; + out.import_name = name_bytes; + + std::mem::forget(ns); + std::mem::forget(name); + match export { Export::Function { .. } => { - let ns = namespace.clone().into_bytes(); - let ns_bytes = wasmer_byte_array { - bytes: ns.as_ptr(), - bytes_len: ns.len() as u32, - }; - std::mem::forget(ns); - - let name = name.clone().into_bytes(); - let name_bytes = wasmer_byte_array { - bytes: name.as_ptr(), - bytes_len: name.len() as u32, - }; - std::mem::forget(name); - let func = Box::new(export.clone()); - let new_entry = wasmer_import_t { - module_name: ns_bytes, - import_name: name_bytes, - tag: wasmer_import_export_kind::WASM_FUNCTION, - value: wasmer_import_export_value { - func: Box::into_raw(func) as *mut _ as *const _, - }, + out.tag = wasmer_import_export_kind::WASM_FUNCTION; + out.value = wasmer_import_export_value { + func: Box::into_raw(func) as *mut _ as *const _, }; - *imports.add(i as usize) = new_entry; - i += 1; } - _ => (), - } - } + Export::Global(global) => { + let glbl = Box::new(global.clone()); - return i as i32; + out.tag = wasmer_import_export_kind::WASM_GLOBAL; + out.value = wasmer_import_export_value { + global: Box::into_raw(glbl) as *mut _ as *const _, + }; + } + Export::Memory(memory) => { + let mem = Box::new(memory.clone()); + + out.tag = wasmer_import_export_kind::WASM_MEMORY; + out.value = wasmer_import_export_value { + memory: Box::into_raw(mem) as *mut _ as *const _, + }; + } + Export::Table(table) => { + let tbl = Box::new(table.clone()); + + out.tag = wasmer_import_export_kind::WASM_TABLE; + out.value = wasmer_import_export_value { + memory: Box::into_raw(tbl) as *mut _ as *const _, + }; + } + } + + wasmer_result_t::WASMER_OK + } else { + wasmer_result_t::WASMER_ERROR + } } +/// Returns true if further calls to `wasmer_import_object_iter_next` will +/// not return any new data #[no_mangle] -/// Frees the memory acquired in `wasmer_import_object_get_functions` +pub unsafe extern "C" fn wasmer_import_object_iter_at_end( + import_object_iter: *mut wasmer_import_object_iter_t, +) -> bool { + if import_object_iter.is_null() { + update_last_error(CApiError { + msg: "import_object_iter must not be null".to_owned(), + }); + return true; + } + let iter = &mut *(import_object_iter as *mut WasmerImportObjectIterator); + + iter.0.peek().is_none() +} + +/// Frees the memory allocated by `wasmer_import_object_iterate_functions` +#[no_mangle] +pub unsafe extern "C" fn wasmer_import_object_iter_destroy( + import_object_iter: *mut wasmer_import_object_iter_t, +) { + let _ = Box::from_raw(import_object_iter as *mut WasmerImportObjectIterator); +} + +/// Frees the memory allocated in `wasmer_import_object_iter_next` /// /// This function does not free the memory in `wasmer_import_object_t`; /// it only frees memory allocated while querying a `wasmer_import_object_t`. +#[no_mangle] pub unsafe extern "C" fn wasmer_import_object_imports_destroy( imports: *mut wasmer_import_t, imports_len: u32, diff --git a/lib/runtime-c-api/tests/test-wasi-import-object b/lib/runtime-c-api/tests/test-wasi-import-object index 70e24d17d8b27c47e5810e79983e2fe5e4b8779d..912bc8c0d7c62e00ceb3a3dabe9d541f58305382 100755 GIT binary patch delta 4052 zcmZu!ZBSI#89sa2)dg7=M3IkOc9E}DAt)2ATG8c8F9aJhF$tqa*udIFVHaUZu%j-O zY~pp@6g-kTY0}^i4HHeJqhtuG=_NlzULkYZhD8k z&-1+JIq!Mzx#!$_Iel0&v9nuBu#!g)YtI|YW-pE-L<8|Fv1;SuxSl(!XFp6;qha3T zVJa=utezcCQ^S4O1CDSS-3#Gvvl>nj)Nr?%Uem0ed%~iItJNq$EzsM#G-?-8uo{*n zp0`@*HepQ`kLr1lfR38vfHUA{qnCxeN#kU1{r@p8pysG4qn($W9ATUZ85hy!s71P( z45+B5IE@ZPEl6G*Q5|SJCg^uj)>R;|Ks_Ljv&Q8h>{>!P9w(#)A~+k#@C$=R->Maa zjL>Ja7R^GO1zq@Oggo8zR3h!y+Ts)czB@7d#budq|8>(FX_{}+=q>GXq1s4Ob$^&G zLjoLd0sP`w!c(_(&*~4FlX4A-P^cK#eP8-et~3xLO64+0S$2Ss%D-T|!a$46^J4Wz zY(GChz`A6|`rQih? z2o5pm9RQFiEaqbAT$!|f6pCZ1r1CMCG^BF-RO^k4{*Nb86ot)SP&bPW?H^%<==3r4 zqxmLb$xJ#v-(*Xi>NIrGe;ORT&n0yp`qe&T(KJ8PBwU?Ap8)vd4BD8vpomo*V3kz` z)T#r$STz)X0-#*_1gcc)*JhOk-ojv+v^h&Je>sC*%{2S^ARtN?VG@uH;U0q3ahOGM zb#w!h$8``5_*t}TWHBsoF*w+Pvo2j11HI@0>prxeRjtUyDeL`6YbRPMShbM0lX|k| z&13_4bTpV{vf@DUATb!DfgdeQaVkNv>x!q9Rp?aN-6 z-+=r{XqNm9&^a)OXQ=QMxPP!o&Ct>n!k9+#*U@{~1*u=dvlME-%fL_pzTpqC!~;>( zo@2AEWVtr5TzH0D>1wW*;ep&0!WiV*OuKUmQa7r(YSdi+1Q;H}Twe?H)10E*GY}~L z03X0|Idqo%t5{k*L)xRz3MGCd(4yS=g*9*?#+Ttuf%E$wo93m*85nk8-cK>hT3ChS zK*)Ywub%egruaOnvsrakq4P6z>L;BrtKBf39E1SO-C}j@rC^lvASC%Wz`$U_2KiZt zJg)R>jDE;R##cb;yb0D8L5H37nSefBAvpUKjq%XA&bvzIZH@8$b7Fm1?0QJ1uHzcs zx8Tw-28NrEbodTdw;d9*>kxw>mUi=h73EJ>Y&wWz27?$CyUxXn(pAY{4a3PR&;mP_ z$R4nCg{y3xbcm7A|yaS^@5bLjsUEjeaRe^u123#Ca!+Ny_oUdUVT9)CY*3cEQ zVJ>4Yjmt^)#j5@o)i0v|-{?O&{}BHM=S9J0Do&is(Zytdt4?``zB z+pLXlYh!bZr`2oqys*t#?_C)~XwPGFW~f2BryyyP9w}H9haaHueZziAD*dcrbx)nv zr{$lNaU7F5&gYoNaT!ND$4ZVHIBwzS;@HY@7sppP5|jGD7o(z&%;AA_jy8^k99MB% z%dwi{Mve^}-5fhO?&WxZk9zGWw>I#snfy{KHET3Q?3 z-mR!wP_=vOU5-|i9ja_Q^{suThCWx4s2Qar#VPTPUT15q!&~cgH=u0{gIWyIEhQ=R z<6=V`bGV%yY>Zpjo`fNX*IB!Daxr07nQkvJX~J}0Nsi_|Jy~KAIt6;SWNvJe)BQ`Y z3oZLFU^R6M3HI8T9Bs`oG+d0Qb!TmZ!|OoDVVYlR*7VUQN=+;Je`<3(UqaWw^cGJ; zdy})a!P(|*^{`nPqJ5<{%?Q0zYDyiQ=JYyV03%N^MwQZq)K>O$VZcP4WtN;iGyDtF znGUD1bXe!?7%;WeRRcQ)`#LU~keUqoZdrQax}vAr*j zJ}7(9@q3V<;PIm#M(rWEW6(Nz$oHmD@G&3C5290oh+SLI3~& delta 4180 zcmZu!4Nw&48QwkaT$#>QH};}k1@MXo}Pz0=FK zZr7`rPaL#yWF~2%t&L0&OGqyPwP?~Nf-_c{I2pCpS!PUn(L_P1*Z2K)0l8-9ZlC9Q zzxR8;XTSZv-MjIYv+ZoFV6-#S5Bs5G%i|y4q*WTthiRc*^%j777T19SYW)p`hncRv5$)~C%6Nv_;G3t8~7ZG#BWTIU$X$nh>gaYZLHX=jAWx?2o zif5Cah;)-f_Q6cl2aQKA8H=zMI%I=UfKYAnSOGc+ZfzwD(*RMteiM8ASM=#wUdryx*<;GWC<3dE};gh02;nQZ(pN^8Q$~h-=T@7=79YyTA#6_72;Fc5jj0yu%wT@vpp;Q7XNgfbF=^e_q=}4_E zDb4^DIN^LJBMoawt1fx1ndXd(?s3jv^e;WbK+`F>{hV{pxKMge5|Im~K`0W0Bmr{YLD)niKW} zFY%`#4%Y+aA8|srbvzUjJ}d6QOXY+%6UcSKc~0OB*x-+Yv-EBpb`M~L6KRiLoMle* zV|t0mW0q0s!8C#IpyO(;>4>Da7IFzuLvANI zF)JyO4s>D$3Cv2h;y}`eSjk^h7LAbS1Q7Vs*syvA8Jm@vk|8&wQ_yY$=sgGSrMnv9 zNHi@9YS2i)3$rKiC$Zlhj0k))&ZihakgjWpCoxI&o`$q1rlq`vS$n7YL2^5WwrI#; z;^NH1$XlRU;H#js*o|j!_*=Mtut{Hp7GD5ktiZRDMM+Cjp5VOs^TsG>UxvKi0kn8d zO&XGHwvDvbdRhz5P-~%F>nv<>UjSoJ>j3G4T3h5=6>_bw0D1?pmRU`rO+||?LZJA4 zdm~uN>_5~0aeOtfxn~?Vwt3Nm7;hg6=-zYQbT*5o$&$~-O zdmU``-o|0xgu2wZ;s@3?78Bdhixff4Ede^++`qq_W^Nu75vjM8JSOW8dnT>)bIw7| z_jt-lx$I=K?Bqx21Pw?j6Hdf#tO2vV3EJRBJP!?*cpJnZ4d&`KxFaIf%4mKY+)CIR zbTXWN%=BuXW+7X zzror|ptdse&pMwl?rXNe9X;>8AM)OYJ9?jU4othDDRNnpTy{5>y^m$D!D)o?&@-Im ziSqTq*1+o>8NfG=NEeJe&(czQjWiJsN zq9Le{Z6$`;U&eneuz-xu-r%_ggNz)3ol>pFb#wq(7P5WFUP9K4 z%#ExLSsSt{Wap5*f@~OB8L|h+)*v(Djx9v?9I|X=95NfSt;o{geut_LB2B>HX=E|T z{)&u22A9B$JcNm@#_c_F57`oAw~-Yf8%DMk*=NXb4o5B`t3cL^tQJ`(vR@#38`*wf zi$~r-dIW>7BYO+keq`?<`z5k|WKCUubAZj+>aKH^S2i|QwlH<>+H#al+w1FgT8oOT z7-)1gxf|JJoN~_RVCkB{3{=+>)WgU+%du7JlLP`9CbH zJU8G{;SMo(6$~o)SV48B+^$p5q~KfymngVQL5G4bD7aq1pD1`QL$3EwM%WI@Krsp? zD43?8O~Gsh3l&_WV3~riC|IRnor28@?o;r9f=4LA|BDVK@COCYD)^y-mleE=vLDW{()YLmsRiJX!IvZM0 zRm*Cps|i&DsD{Svbxm7QHKTGjIjbuhyB^vjS?xAg)6{w(aoK5!7@4+8u-_mtW~Y#+ zS@G;J>CH}MZ<6cT3t5Rg&9zj_+f_zK`L4>HwXR0=T;JGIUgz3{-8#rnj+s44{*z;4JBcYbm3*BOr)#R*QsbIP z=_4=YE+#Fx1uAa=>CUw*3>LuOw852d>L`R2M-Oj7Lq!=d7i>ozJWaSP@;Emwd*UzV zTxin6^0cPOtH!42LFF$f?oMoPFq0SZeqMPTBq(@7$OrDVXZ0V$bXS=EAWUBf(|;p# zmYwjNf|BwFn&B7<(~rWm7W_P$pBbjtgz1Vfy?eTjXAVveFmIFM<(8MPghlU$=_r`u zXKkc~X?vJnPi`%L2Osbb_%+95lCPHkjuhq}jezw|uIA?xW5Gb!itH;$GXCF+Bz*<; Ku01Q8+5Z6}_`S3M diff --git a/lib/runtime-c-api/tests/test-wasi-import-object.c b/lib/runtime-c-api/tests/test-wasi-import-object.c index cf4a145d5..e3f530d2d 100644 --- a/lib/runtime-c-api/tests/test-wasi-import-object.c +++ b/lib/runtime-c-api/tests/test-wasi-import-object.c @@ -217,34 +217,26 @@ int main() assert(call_result == WASMER_OK); assert(host_print_called); - int32_t num_functions = wasmer_import_object_get_num_functions(import_object); - if (num_functions == -1) { - print_wasmer_error(); - return -1; - } - wasmer_import_t *func_array = malloc(sizeof(wasmer_import_t) * num_functions); - assert(func_array); + wasmer_import_object_iter_t *func_iter = wasmer_import_object_iterate_functions(import_object); - int32_t num_returned = wasmer_import_object_get_functions(import_object, func_array, num_functions); - if (num_functions == -1) { - print_wasmer_error(); - return -1; - } - assert(num_functions == num_returned); + puts("Functions in import object:"); + while ( !wasmer_import_object_iter_at_end(func_iter) ) { + wasmer_import_t import; + wasmer_result_t result = wasmer_import_object_iter_next(func_iter, &import); + assert(result == WASMER_OK); - printf("Found %d functions in import object:\n", num_returned); - for (int i = 0; i < num_returned; ++i) { - print_byte_array(&func_array[i].module_name); + print_byte_array(&import.module_name); putchar(' '); - print_byte_array(&func_array[i].import_name); + print_byte_array(&import.import_name); putchar('\n'); - assert(func_array[i].tag == WASM_FUNCTION); - assert(func_array[i].value.func); + + assert(import.tag == WASM_FUNCTION); + assert(import.value.func); + wasmer_import_object_imports_destroy(&import, 1); } + wasmer_import_object_iter_destroy(func_iter); // Use *_destroy methods to cleanup as specified in the header documentation - wasmer_import_object_imports_destroy(func_array, num_returned); - free(func_array); wasmer_import_func_destroy(func); wasmer_global_destroy(global); wasmer_memory_destroy(memory); diff --git a/lib/runtime-c-api/wasmer.h b/lib/runtime-c-api/wasmer.h index 8bb9fb254..eb9dab50d 100644 --- a/lib/runtime-c-api/wasmer.h +++ b/lib/runtime-c-api/wasmer.h @@ -138,6 +138,10 @@ typedef struct { typedef struct { +} wasmer_import_object_iter_t; + +typedef struct { + } wasmer_instance_t; typedef struct { @@ -469,22 +473,13 @@ wasmer_result_t wasmer_import_object_extend(wasmer_import_object_t *import_objec const wasmer_import_t *imports, unsigned int imports_len); -/** - * Call `wasmer_import_object_imports_destroy` to free the memory allocated by this function. - * This function return -1 on error. - */ -int32_t wasmer_import_object_get_functions(const wasmer_import_object_t *import_object, - wasmer_import_t *imports, - uint32_t imports_len); - /** * Gets an entry from an ImportObject at the name and namespace. - * Stores an immutable reference to `name` and `namespace` in `import`. + * Stores `name`, `namespace`, and `import_export_value` in `import`. + * Thus these must remain valid for the lifetime of `import`. * * The caller owns all data involved. - * `import_export_value` will be written to based on `tag`, `import_export_value` must be - * initialized to point to the type specified by `tag`. Failure to do so may result - * in data corruption or undefined behavior. + * `import_export_value` will be written to based on `tag`. */ wasmer_result_t wasmer_import_object_get_import(const wasmer_import_object_t *import_object, wasmer_byte_array namespace_, @@ -494,20 +489,41 @@ wasmer_result_t wasmer_import_object_get_import(const wasmer_import_object_t *im uint32_t tag); /** - * Get the number of functions that an import object contains. - * The result of this is useful as an argument to `wasmer_import_object_get_functions`. - * This function returns -1 on error. - */ -int32_t wasmer_import_object_get_num_functions(const wasmer_import_object_t *import_object); - -/** - * Frees the memory acquired in `wasmer_import_object_get_functions` + * Frees the memory allocated in `wasmer_import_object_iter_next` * * This function does not free the memory in `wasmer_import_object_t`; * it only frees memory allocated while querying a `wasmer_import_object_t`. */ void wasmer_import_object_imports_destroy(wasmer_import_t *imports, uint32_t imports_len); +/** + * Returns true if further calls to `wasmer_import_object_iter_next` will + * not return any new data + */ +bool wasmer_import_object_iter_at_end(wasmer_import_object_iter_t *import_object_iter); + +/** + * Frees the memory allocated by `wasmer_import_object_iterate_functions` + */ +void wasmer_import_object_iter_destroy(wasmer_import_object_iter_t *import_object_iter); + +/** + * Writes the next value to `import`. `WASMER_ERROR` is returned if there + * was an error or there's nothing left to return. + * + * To free the memory allocated here, pass the import to `wasmer_import_object_imports_destroy`. + * To check if the iterator is done, use `wasmer_import_object_iter_at_end`. + */ +wasmer_result_t wasmer_import_object_iter_next(wasmer_import_object_iter_t *import_object_iter, + wasmer_import_t *import); + +/** + * Create an iterator over the functions in the import object. + * Get the next import with `wasmer_import_object_iter_next` + * Free the iterator with `wasmer_import_object_iter_destroy` + */ +wasmer_import_object_iter_t *wasmer_import_object_iterate_functions(const wasmer_import_object_t *import_object); + /** * Creates a new empty import object. * See also `wasmer_import_object_append` diff --git a/lib/runtime-c-api/wasmer.hh b/lib/runtime-c-api/wasmer.hh index 21426f278..04a095c48 100644 --- a/lib/runtime-c-api/wasmer.hh +++ b/lib/runtime-c-api/wasmer.hh @@ -120,6 +120,10 @@ struct wasmer_import_t { wasmer_import_export_value value; }; +struct wasmer_import_object_iter_t { + +}; + struct wasmer_instance_t { }; @@ -371,19 +375,12 @@ wasmer_result_t wasmer_import_object_extend(wasmer_import_object_t *import_objec const wasmer_import_t *imports, unsigned int imports_len); -/// Call `wasmer_import_object_imports_destroy` to free the memory allocated by this function. -/// This function return -1 on error. -int32_t wasmer_import_object_get_functions(const wasmer_import_object_t *import_object, - wasmer_import_t *imports, - uint32_t imports_len); - /// Gets an entry from an ImportObject at the name and namespace. -/// Stores an immutable reference to `name` and `namespace` in `import`. +/// Stores `name`, `namespace`, and `import_export_value` in `import`. +/// Thus these must remain valid for the lifetime of `import`. /// /// The caller owns all data involved. -/// `import_export_value` will be written to based on `tag`, `import_export_value` must be -/// initialized to point to the type specified by `tag`. Failure to do so may result -/// in data corruption or undefined behavior. +/// `import_export_value` will be written to based on `tag`. wasmer_result_t wasmer_import_object_get_import(const wasmer_import_object_t *import_object, wasmer_byte_array namespace_, wasmer_byte_array name, @@ -391,17 +388,32 @@ wasmer_result_t wasmer_import_object_get_import(const wasmer_import_object_t *im wasmer_import_export_value *import_export_value, uint32_t tag); -/// Get the number of functions that an import object contains. -/// The result of this is useful as an argument to `wasmer_import_object_get_functions`. -/// This function returns -1 on error. -int32_t wasmer_import_object_get_num_functions(const wasmer_import_object_t *import_object); - -/// Frees the memory acquired in `wasmer_import_object_get_functions` +/// Frees the memory allocated in `wasmer_import_object_iter_next` /// /// This function does not free the memory in `wasmer_import_object_t`; /// it only frees memory allocated while querying a `wasmer_import_object_t`. void wasmer_import_object_imports_destroy(wasmer_import_t *imports, uint32_t imports_len); +/// Returns true if further calls to `wasmer_import_object_iter_next` will +/// not return any new data +bool wasmer_import_object_iter_at_end(wasmer_import_object_iter_t *import_object_iter); + +/// Frees the memory allocated by `wasmer_import_object_iterate_functions` +void wasmer_import_object_iter_destroy(wasmer_import_object_iter_t *import_object_iter); + +/// Writes the next value to `import`. `WASMER_ERROR` is returned if there +/// was an error or there's nothing left to return. +/// +/// To free the memory allocated here, pass the import to `wasmer_import_object_imports_destroy`. +/// To check if the iterator is done, use `wasmer_import_object_iter_at_end`. +wasmer_result_t wasmer_import_object_iter_next(wasmer_import_object_iter_t *import_object_iter, + wasmer_import_t *import); + +/// Create an iterator over the functions in the import object. +/// Get the next import with `wasmer_import_object_iter_next` +/// Free the iterator with `wasmer_import_object_iter_destroy` +wasmer_import_object_iter_t *wasmer_import_object_iterate_functions(const wasmer_import_object_t *import_object); + /// Creates a new empty import object. /// See also `wasmer_import_object_append` wasmer_import_object_t *wasmer_import_object_new();