mirror of
https://github.com/fluencelabs/wasmer
synced 2025-06-21 12:41:32 +00:00
Update ImportObject C API to use iterators
This commit is contained in:
@ -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<Box<dyn Iterator<Item = <ImportObjectIterator as Iterator>::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)| {
|
||||
let iter_inner = Box::new(import_object.clone_ref().into_iter().filter(|(_, _, e)| {
|
||||
if let Export::Function { .. } = e {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
.count() as i32
|
||||
})) as Box<dyn Iterator<Item = <ImportObjectIterator as Iterator>::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;
|
||||
}
|
||||
match export {
|
||||
Export::Function { .. } => {
|
||||
let ns = namespace.clone().into_bytes();
|
||||
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,
|
||||
};
|
||||
std::mem::forget(ns);
|
||||
|
||||
let name = name.clone().into_bytes();
|
||||
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 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 {
|
||||
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());
|
||||
|
||||
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 _,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return i as i32;
|
||||
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,
|
||||
|
Binary file not shown.
@ -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);
|
||||
|
@ -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`
|
||||
|
@ -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();
|
||||
|
Reference in New Issue
Block a user