mirror of
https://github.com/mii443/wasmer.git
synced 2025-12-08 21:58:20 +00:00
feat(c-api) Allow extern types to own data.
We have known memory leaks with extern types. The idea is to change the code so that extern types can hold/own data. This patch does that. A `wasm_externtype_t` holds a `WasmExternType` enum. This enum owns sibling types such as `WasmFunctionType`, `WasmGlobalType`, `WasmTableType` and `WasmMemoryType`. It is those structures that ows the extern types data, like `params` and `results` as `wasm_valtype_vec_t` for `WasmFunctionType`. That way, for example, `wasm_functype_t` can return a pointer to these vec which it owns. A `wasm_externtype_t` continues to be transmuted to `wasm_functype_t` etc. Nothing changes on that side.
This commit is contained in:
@@ -33,11 +33,11 @@ pub type wasm_env_finalizer_t = unsafe extern "C" fn(c_void);
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasm_func_new(
|
||||
store: &wasm_store_t,
|
||||
ft: &wasm_functype_t,
|
||||
function_type: &wasm_functype_t,
|
||||
callback: wasm_func_callback_t,
|
||||
) -> Option<Box<wasm_func_t>> {
|
||||
// TODO: handle null pointers?
|
||||
let func_sig = ft.sig();
|
||||
let func_sig = &function_type.inner().function_type;
|
||||
let num_rets = func_sig.results().len();
|
||||
let inner_callback = move |args: &[Val]| -> Result<Vec<Val>, RuntimeError> {
|
||||
let processed_args: wasm_val_vec_t = args
|
||||
@@ -85,13 +85,13 @@ pub unsafe extern "C" fn wasm_func_new(
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasm_func_new_with_env(
|
||||
store: &wasm_store_t,
|
||||
ft: &wasm_functype_t,
|
||||
function_type: &wasm_functype_t,
|
||||
callback: wasm_func_callback_with_env_t,
|
||||
env: *mut c_void,
|
||||
finalizer: wasm_env_finalizer_t,
|
||||
) -> Option<Box<wasm_func_t>> {
|
||||
// TODO: handle null pointers?
|
||||
let func_sig = ft.sig();
|
||||
let func_sig = &function_type.inner().function_type;
|
||||
let num_rets = func_sig.results().len();
|
||||
let inner_callback =
|
||||
move |env: &mut *mut c_void, args: &[Val]| -> Result<Vec<Val>, RuntimeError> {
|
||||
|
||||
6
lib/c-api/src/wasm_c_api/externals/global.rs
vendored
6
lib/c-api/src/wasm_c_api/externals/global.rs
vendored
@@ -13,13 +13,13 @@ pub struct wasm_global_t {
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasm_global_new(
|
||||
store: &wasm_store_t,
|
||||
gt: &wasm_globaltype_t,
|
||||
global_type: &wasm_globaltype_t,
|
||||
val: &wasm_val_t,
|
||||
) -> Option<Box<wasm_global_t>> {
|
||||
let gt = gt.as_globaltype();
|
||||
let global_type = &global_type.inner().global_type;
|
||||
let wasm_val = val.try_into().ok()?;
|
||||
let store = &store.inner;
|
||||
let global = if gt.mutability.is_mutable() {
|
||||
let global = if global_type.mutability.is_mutable() {
|
||||
Global::new_mut(store, wasm_val)
|
||||
} else {
|
||||
Global::new(store, wasm_val)
|
||||
|
||||
6
lib/c-api/src/wasm_c_api/externals/memory.rs
vendored
6
lib/c-api/src/wasm_c_api/externals/memory.rs
vendored
@@ -12,10 +12,10 @@ pub struct wasm_memory_t {
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasm_memory_new(
|
||||
store: &wasm_store_t,
|
||||
mt: &wasm_memorytype_t,
|
||||
memory_type: &wasm_memorytype_t,
|
||||
) -> Option<Box<wasm_memory_t>> {
|
||||
let md = mt.as_memorytype().clone();
|
||||
let memory = c_try!(Memory::new(&store.inner, md));
|
||||
let memory_type = memory_type.inner().memory_type.clone();
|
||||
let memory = c_try!(Memory::new(&store.inner, memory_type));
|
||||
|
||||
Some(Box::new(wasm_memory_t { inner: memory }))
|
||||
}
|
||||
|
||||
6
lib/c-api/src/wasm_c_api/externals/table.rs
vendored
6
lib/c-api/src/wasm_c_api/externals/table.rs
vendored
@@ -11,12 +11,12 @@ pub struct wasm_table_t {
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasm_table_new(
|
||||
store: &wasm_store_t,
|
||||
tt: &wasm_tabletype_t,
|
||||
table_type: &wasm_tabletype_t,
|
||||
init: *const wasm_ref_t,
|
||||
) -> Option<Box<wasm_table_t>> {
|
||||
let tt = tt.as_tabletype().clone();
|
||||
let table_type = table_type.inner().table_type.clone();
|
||||
let init_val = todo!("get val from init somehow");
|
||||
let table = c_try!(Table::new(&store.inner, tt, init_val));
|
||||
let table = c_try!(Table::new(&store.inner, table_type, init_val));
|
||||
|
||||
Some(Box::new(wasm_table_t { inner: table }))
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ macro_rules! wasm_declare_vec_inner {
|
||||
macro_rules! wasm_declare_vec {
|
||||
($name:ident) => {
|
||||
paste::item! {
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct [<wasm_ $name _vec_t>] {
|
||||
pub size: usize,
|
||||
@@ -108,6 +109,7 @@ macro_rules! wasm_declare_vec {
|
||||
macro_rules! wasm_declare_boxed_vec {
|
||||
($name:ident) => {
|
||||
paste::item! {
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct [<wasm_ $name _vec_t>] {
|
||||
pub size: usize,
|
||||
|
||||
@@ -259,11 +259,9 @@ mod tests {
|
||||
wasmer_assert(func_params->size == 2);
|
||||
wasmer_assert(wasm_valtype_kind(func_params->data[0]) == WASM_I32);
|
||||
wasmer_assert(wasm_valtype_kind(func_params->data[1]) == WASM_I64);
|
||||
wasm_valtype_vec_delete((wasm_valtype_vec_t*) func_params);
|
||||
|
||||
const wasm_valtype_vec_t* func_results = wasm_functype_results(func_type);
|
||||
wasmer_assert(func_results->size == 0);
|
||||
wasm_valtype_vec_delete((wasm_valtype_vec_t*) func_results);
|
||||
}
|
||||
|
||||
{
|
||||
@@ -366,11 +364,9 @@ mod tests {
|
||||
|
||||
const wasm_valtype_vec_t* func_params = wasm_functype_params(func_type);
|
||||
wasmer_assert(func_params->size == 0);
|
||||
wasm_valtype_vec_delete((wasm_valtype_vec_t*) func_params);
|
||||
|
||||
const wasm_valtype_vec_t* func_results = wasm_functype_results(func_type);
|
||||
wasmer_assert(func_results->size == 0);
|
||||
wasm_valtype_vec_delete((wasm_valtype_vec_t*) func_results);
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
@@ -1,47 +1,13 @@
|
||||
use super::super::externals::wasm_extern_t;
|
||||
use super::{wasm_functype_t, wasm_globaltype_t, wasm_memorytype_t, wasm_tabletype_t};
|
||||
use super::{
|
||||
wasm_functype_t, wasm_globaltype_t, wasm_memorytype_t, wasm_tabletype_t, WasmFunctionType,
|
||||
WasmGlobalType, WasmMemoryType, WasmTableType,
|
||||
};
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
use std::mem;
|
||||
use thiserror::Error;
|
||||
use wasmer::ExternType;
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct wasm_externtype_t {
|
||||
pub(crate) inner: ExternType,
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasm_extern_type(e: &wasm_extern_t) -> Box<wasm_externtype_t> {
|
||||
Box::new(wasm_externtype_t {
|
||||
inner: e.inner.ty(),
|
||||
})
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasm_externtype_delete(_et: Option<Box<wasm_externtype_t>>) {}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn wasm_externtype_copy(
|
||||
wasm_externtype: &wasm_externtype_t,
|
||||
) -> Box<wasm_externtype_t> {
|
||||
Box::new(wasm_externtype_t {
|
||||
inner: wasm_externtype.inner.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
impl From<ExternType> for wasm_externtype_t {
|
||||
fn from(other: ExternType) -> Self {
|
||||
Self { inner: other }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&ExternType> for wasm_externtype_t {
|
||||
fn from(other: &ExternType) -> Self {
|
||||
other.clone().into()
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
type wasm_externkind_t = u8;
|
||||
|
||||
@@ -54,11 +20,6 @@ pub enum wasm_externkind_enum {
|
||||
WASM_EXTERN_MEMORY = 3,
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasm_extern_kind(e: &wasm_extern_t) -> wasm_externkind_t {
|
||||
wasm_externkind_enum::from(e.inner.ty()) as wasm_externkind_t
|
||||
}
|
||||
|
||||
impl From<ExternType> for wasm_externkind_enum {
|
||||
fn from(other: ExternType) -> Self {
|
||||
(&other).into()
|
||||
@@ -75,9 +36,81 @@ impl From<&ExternType> for wasm_externkind_enum {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) enum WasmExternType {
|
||||
Function(WasmFunctionType),
|
||||
Global(WasmGlobalType),
|
||||
Table(WasmTableType),
|
||||
Memory(WasmMemoryType),
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct wasm_externtype_t {
|
||||
pub(crate) inner: WasmExternType,
|
||||
}
|
||||
|
||||
impl wasm_externtype_t {
|
||||
pub(crate) fn new(extern_type: ExternType) -> Self {
|
||||
Self {
|
||||
inner: match extern_type {
|
||||
ExternType::Function(function_type) => {
|
||||
WasmExternType::Function(WasmFunctionType::new(function_type))
|
||||
}
|
||||
ExternType::Global(global_type) => {
|
||||
WasmExternType::Global(WasmGlobalType::new(global_type))
|
||||
}
|
||||
ExternType::Table(table_type) => {
|
||||
WasmExternType::Table(WasmTableType::new(table_type))
|
||||
}
|
||||
ExternType::Memory(memory_type) => {
|
||||
WasmExternType::Memory(WasmMemoryType::new(memory_type))
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ExternType> for wasm_externtype_t {
|
||||
fn from(extern_type: ExternType) -> Self {
|
||||
Self::new(extern_type)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&ExternType> for wasm_externtype_t {
|
||||
fn from(other: &ExternType) -> Self {
|
||||
other.clone().into()
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasm_externtype_kind(et: &wasm_externtype_t) -> wasm_externkind_t {
|
||||
wasm_externkind_enum::from(&et.inner) as wasm_externkind_t
|
||||
pub unsafe extern "C" fn wasm_extern_type(e: &wasm_extern_t) -> Box<wasm_externtype_t> {
|
||||
Box::new(wasm_externtype_t::new(e.inner.ty()))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasm_extern_kind(r#extern: &wasm_extern_t) -> wasm_externkind_t {
|
||||
wasm_externkind_enum::from(r#extern.inner.ty()) as wasm_externkind_t
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasm_externtype_delete(_et: Option<Box<wasm_externtype_t>>) {}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn wasm_externtype_copy(externtype: &wasm_externtype_t) -> Box<wasm_externtype_t> {
|
||||
Box::new(externtype.clone())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasm_externtype_kind(
|
||||
extern_type: &wasm_externtype_t,
|
||||
) -> wasm_externkind_t {
|
||||
(match extern_type.inner {
|
||||
WasmExternType::Function(_) => wasm_externkind_enum::WASM_EXTERN_FUNC,
|
||||
WasmExternType::Global(_) => wasm_externkind_enum::WASM_EXTERN_GLOBAL,
|
||||
WasmExternType::Table(_) => wasm_externkind_enum::WASM_EXTERN_TABLE,
|
||||
WasmExternType::Memory(_) => wasm_externkind_enum::WASM_EXTERN_MEMORY,
|
||||
}) as wasm_externkind_t
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Error)]
|
||||
@@ -94,7 +127,7 @@ impl TryFrom<&'static wasm_externtype_t> for &'static wasm_functype_t {
|
||||
type Error = ExternTypeConversionError;
|
||||
|
||||
fn try_from(other: &'static wasm_externtype_t) -> Result<Self, Self::Error> {
|
||||
if let ExternType::Function(_) = other.inner {
|
||||
if let WasmExternType::Function(_) = other.inner {
|
||||
Ok(unsafe { mem::transmute::<&'static wasm_externtype_t, Self>(other) })
|
||||
} else {
|
||||
Err(ExternTypeConversionError("Wrong type: expected function"))
|
||||
@@ -106,7 +139,7 @@ impl TryFrom<&'static wasm_externtype_t> for &'static wasm_globaltype_t {
|
||||
type Error = ExternTypeConversionError;
|
||||
|
||||
fn try_from(other: &'static wasm_externtype_t) -> Result<Self, Self::Error> {
|
||||
if let ExternType::Global(_) = other.inner {
|
||||
if let WasmExternType::Global(_) = other.inner {
|
||||
Ok(unsafe { mem::transmute::<&'static wasm_externtype_t, Self>(other) })
|
||||
} else {
|
||||
Err(ExternTypeConversionError("Wrong type: expected global"))
|
||||
@@ -114,23 +147,11 @@ impl TryFrom<&'static wasm_externtype_t> for &'static wasm_globaltype_t {
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&'static wasm_externtype_t> for &'static wasm_memorytype_t {
|
||||
type Error = ExternTypeConversionError;
|
||||
|
||||
fn try_from(other: &'static wasm_externtype_t) -> Result<Self, Self::Error> {
|
||||
if let ExternType::Memory(_) = other.inner {
|
||||
Ok(unsafe { mem::transmute::<&'static wasm_externtype_t, Self>(other) })
|
||||
} else {
|
||||
Err(ExternTypeConversionError("Wrong type: expected memory"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&'static wasm_externtype_t> for &'static wasm_tabletype_t {
|
||||
type Error = ExternTypeConversionError;
|
||||
|
||||
fn try_from(other: &'static wasm_externtype_t) -> Result<Self, Self::Error> {
|
||||
if let ExternType::Table(_) = other.inner {
|
||||
if let WasmExternType::Table(_) = other.inner {
|
||||
Ok(unsafe { mem::transmute::<&'static wasm_externtype_t, Self>(other) })
|
||||
} else {
|
||||
Err(ExternTypeConversionError("Wrong type: expected table"))
|
||||
@@ -138,114 +159,126 @@ impl TryFrom<&'static wasm_externtype_t> for &'static wasm_tabletype_t {
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&'static wasm_externtype_t> for &'static wasm_memorytype_t {
|
||||
type Error = ExternTypeConversionError;
|
||||
|
||||
fn try_from(other: &'static wasm_externtype_t) -> Result<Self, Self::Error> {
|
||||
if let WasmExternType::Memory(_) = other.inner {
|
||||
Ok(unsafe { mem::transmute::<&'static wasm_externtype_t, Self>(other) })
|
||||
} else {
|
||||
Err(ExternTypeConversionError("Wrong type: expected memory"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasm_externtype_as_functype_const(
|
||||
et: &'static wasm_externtype_t,
|
||||
extern_type: &'static wasm_externtype_t,
|
||||
) -> Option<&'static wasm_functype_t> {
|
||||
Some(c_try!(et.try_into()))
|
||||
Some(c_try!(extern_type.try_into()))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasm_externtype_as_functype(
|
||||
et: &'static wasm_externtype_t,
|
||||
extern_type: &'static wasm_externtype_t,
|
||||
) -> Option<&'static wasm_functype_t> {
|
||||
Some(c_try!(et.try_into()))
|
||||
Some(c_try!(extern_type.try_into()))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasm_functype_as_externtype_const(
|
||||
ft: &'static wasm_functype_t,
|
||||
function_type: &'static wasm_functype_t,
|
||||
) -> &'static wasm_externtype_t {
|
||||
&ft.extern_
|
||||
&function_type.extern_type
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasm_functype_as_externtype(
|
||||
ft: &'static wasm_functype_t,
|
||||
function_type: &'static wasm_functype_t,
|
||||
) -> &'static wasm_externtype_t {
|
||||
&ft.extern_
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasm_externtype_as_memorytype_const(
|
||||
et: &'static wasm_externtype_t,
|
||||
) -> Option<&'static wasm_memorytype_t> {
|
||||
Some(c_try!(et.try_into()))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasm_externtype_as_memorytype(
|
||||
et: &'static wasm_externtype_t,
|
||||
) -> Option<&'static wasm_memorytype_t> {
|
||||
Some(c_try!(et.try_into()))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasm_memorytype_as_externtype_const(
|
||||
mt: &'static wasm_memorytype_t,
|
||||
) -> &'static wasm_externtype_t {
|
||||
&mt.extern_
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasm_memorytype_as_externtype(
|
||||
mt: &'static wasm_memorytype_t,
|
||||
) -> &'static wasm_externtype_t {
|
||||
&mt.extern_
|
||||
&function_type.extern_type
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasm_externtype_as_globaltype_const(
|
||||
et: &'static wasm_externtype_t,
|
||||
extern_type: &'static wasm_externtype_t,
|
||||
) -> Option<&'static wasm_globaltype_t> {
|
||||
Some(c_try!(et.try_into()))
|
||||
Some(c_try!(extern_type.try_into()))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasm_externtype_as_globaltype(
|
||||
et: &'static wasm_externtype_t,
|
||||
extern_type: &'static wasm_externtype_t,
|
||||
) -> Option<&'static wasm_globaltype_t> {
|
||||
Some(c_try!(et.try_into()))
|
||||
Some(c_try!(extern_type.try_into()))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasm_globaltype_as_externtype_const(
|
||||
gt: &'static wasm_globaltype_t,
|
||||
global_type: &'static wasm_globaltype_t,
|
||||
) -> &'static wasm_externtype_t {
|
||||
>.extern_
|
||||
&global_type.extern_type
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasm_globaltype_as_externtype(
|
||||
gt: &'static wasm_globaltype_t,
|
||||
global_type: &'static wasm_globaltype_t,
|
||||
) -> &'static wasm_externtype_t {
|
||||
>.extern_
|
||||
&global_type.extern_type
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasm_externtype_as_tabletype_const(
|
||||
et: &'static wasm_externtype_t,
|
||||
extern_type: &'static wasm_externtype_t,
|
||||
) -> Option<&'static wasm_tabletype_t> {
|
||||
Some(c_try!(et.try_into()))
|
||||
Some(c_try!(extern_type.try_into()))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasm_externtype_as_tabletype(
|
||||
et: &'static wasm_externtype_t,
|
||||
extern_type: &'static wasm_externtype_t,
|
||||
) -> Option<&'static wasm_tabletype_t> {
|
||||
Some(c_try!(et.try_into()))
|
||||
Some(c_try!(extern_type.try_into()))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasm_tabletype_as_externtype_const(
|
||||
tt: &'static wasm_tabletype_t,
|
||||
table_type: &'static wasm_tabletype_t,
|
||||
) -> &'static wasm_externtype_t {
|
||||
&tt.extern_
|
||||
&table_type.extern_type
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasm_tabletype_as_externtype(
|
||||
tt: &'static wasm_tabletype_t,
|
||||
table_type: &'static wasm_tabletype_t,
|
||||
) -> &'static wasm_externtype_t {
|
||||
&tt.extern_
|
||||
&table_type.extern_type
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasm_externtype_as_memorytype_const(
|
||||
extern_type: &'static wasm_externtype_t,
|
||||
) -> Option<&'static wasm_memorytype_t> {
|
||||
Some(c_try!(extern_type.try_into()))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasm_externtype_as_memorytype(
|
||||
extern_type: &'static wasm_externtype_t,
|
||||
) -> Option<&'static wasm_memorytype_t> {
|
||||
Some(c_try!(extern_type.try_into()))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasm_memorytype_as_externtype_const(
|
||||
memory_type: &'static wasm_memorytype_t,
|
||||
) -> &'static wasm_externtype_t {
|
||||
&memory_type.extern_type
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasm_memorytype_as_externtype(
|
||||
memory_type: &'static wasm_memorytype_t,
|
||||
) -> &'static wasm_externtype_t {
|
||||
&memory_type.extern_type
|
||||
}
|
||||
|
||||
@@ -1,28 +1,90 @@
|
||||
use super::{wasm_externtype_t, wasm_valtype_t, wasm_valtype_vec_t};
|
||||
use super::{wasm_externtype_t, wasm_valtype_t, wasm_valtype_vec_t, WasmExternType};
|
||||
use std::mem;
|
||||
use std::ptr::NonNull;
|
||||
use wasmer::{ExternType, FunctionType, ValType};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct WasmFunctionType {
|
||||
pub(crate) function_type: FunctionType,
|
||||
params: Box<wasm_valtype_vec_t>,
|
||||
results: Box<wasm_valtype_vec_t>,
|
||||
}
|
||||
|
||||
impl WasmFunctionType {
|
||||
pub(crate) fn new(function_type: FunctionType) -> Self {
|
||||
let params = {
|
||||
let mut valtypes = function_type
|
||||
.params()
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(Into::into)
|
||||
.map(Box::new)
|
||||
.map(Box::into_raw)
|
||||
.collect::<Vec<*mut wasm_valtype_t>>();
|
||||
|
||||
let valtypes_vec = Box::new(wasm_valtype_vec_t {
|
||||
size: valtypes.len(),
|
||||
data: valtypes.as_mut_ptr(),
|
||||
});
|
||||
|
||||
mem::forget(valtypes);
|
||||
|
||||
valtypes_vec
|
||||
};
|
||||
let results = {
|
||||
let mut valtypes = function_type
|
||||
.results()
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(Into::into)
|
||||
.map(Box::new)
|
||||
.map(Box::into_raw)
|
||||
.collect::<Vec<*mut wasm_valtype_t>>();
|
||||
|
||||
let valtypes_vec = Box::new(wasm_valtype_vec_t {
|
||||
size: valtypes.len(),
|
||||
data: valtypes.as_mut_ptr(),
|
||||
});
|
||||
|
||||
mem::forget(valtypes);
|
||||
|
||||
valtypes_vec
|
||||
};
|
||||
|
||||
Self {
|
||||
function_type,
|
||||
params,
|
||||
results,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for WasmFunctionType {
|
||||
fn clone(&self) -> Self {
|
||||
Self::new(self.function_type.clone())
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Debug)]
|
||||
#[repr(transparent)]
|
||||
pub struct wasm_functype_t {
|
||||
pub(crate) extern_: wasm_externtype_t,
|
||||
pub(crate) extern_type: wasm_externtype_t,
|
||||
}
|
||||
|
||||
impl wasm_functype_t {
|
||||
pub(crate) fn sig(&self) -> &FunctionType {
|
||||
if let ExternType::Function(ref f) = self.extern_.inner {
|
||||
f
|
||||
} else {
|
||||
unreachable!("data corruption: `wasm_functype_t` does not contain a function")
|
||||
pub(crate) fn new(function_type: FunctionType) -> Self {
|
||||
Self {
|
||||
extern_type: wasm_externtype_t::new(ExternType::Function(function_type)),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn new(function_type: FunctionType) -> Self {
|
||||
Self {
|
||||
extern_: wasm_externtype_t {
|
||||
inner: ExternType::Function(function_type),
|
||||
},
|
||||
pub(crate) fn inner(&self) -> &WasmFunctionType {
|
||||
match &self.extern_type.inner {
|
||||
WasmExternType::Function(wasm_function_type) => &wasm_function_type,
|
||||
_ => {
|
||||
unreachable!("Data corruption: `wasm_functype_t` does not contain a function type")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -36,24 +98,18 @@ pub unsafe extern "C" fn wasm_functype_new(
|
||||
// own
|
||||
results: Option<NonNull<wasm_valtype_vec_t>>,
|
||||
) -> Option<Box<wasm_functype_t>> {
|
||||
wasm_functype_new_inner(params?, results?)
|
||||
}
|
||||
let params = params?;
|
||||
let results = results?;
|
||||
|
||||
unsafe fn wasm_functype_new_inner(
|
||||
// own
|
||||
params: NonNull<wasm_valtype_vec_t>,
|
||||
// own
|
||||
results: NonNull<wasm_valtype_vec_t>,
|
||||
) -> Option<Box<wasm_functype_t>> {
|
||||
let params = params.as_ref();
|
||||
let results = results.as_ref();
|
||||
let params: Vec<ValType> = params
|
||||
.as_ref()
|
||||
.into_slice()?
|
||||
.iter()
|
||||
.map(|ptr| **ptr)
|
||||
.map(Into::into)
|
||||
.collect::<Vec<_>>();
|
||||
let results: Vec<ValType> = results
|
||||
.as_ref()
|
||||
.into_slice()?
|
||||
.iter()
|
||||
.map(|ptr| **ptr)
|
||||
@@ -66,51 +122,29 @@ unsafe fn wasm_functype_new_inner(
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasm_functype_delete(_ft: Option<Box<wasm_functype_t>>) {}
|
||||
pub unsafe extern "C" fn wasm_functype_delete(_function_type: Option<Box<wasm_functype_t>>) {}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasm_functype_copy(
|
||||
arg: Option<NonNull<wasm_functype_t>>,
|
||||
function_type: Option<NonNull<wasm_functype_t>>,
|
||||
) -> Option<Box<wasm_functype_t>> {
|
||||
let arg = arg?;
|
||||
let funcsig = arg.as_ref();
|
||||
Some(Box::new(funcsig.clone()))
|
||||
let function_type = function_type?;
|
||||
|
||||
Some(Box::new(wasm_functype_t::new(
|
||||
function_type.as_ref().inner().function_type.clone(),
|
||||
)))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasm_functype_params(ft: &wasm_functype_t) -> *const wasm_valtype_vec_t {
|
||||
let mut valtypes = ft
|
||||
.sig()
|
||||
.params()
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(Into::into)
|
||||
.map(Box::new)
|
||||
.map(Box::into_raw)
|
||||
.collect::<Vec<*mut wasm_valtype_t>>();
|
||||
let out = Box::into_raw(Box::new(wasm_valtype_vec_t {
|
||||
size: valtypes.len(),
|
||||
data: valtypes.as_mut_ptr(),
|
||||
}));
|
||||
mem::forget(valtypes);
|
||||
out as *const _
|
||||
pub unsafe extern "C" fn wasm_functype_params(
|
||||
function_type: &wasm_functype_t,
|
||||
) -> *const wasm_valtype_vec_t {
|
||||
function_type.inner().params.as_ref() as *const _
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasm_functype_results(ft: &wasm_functype_t) -> *const wasm_valtype_vec_t {
|
||||
let mut valtypes = ft
|
||||
.sig()
|
||||
.results()
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(Into::into)
|
||||
.map(Box::new)
|
||||
.map(Box::into_raw)
|
||||
.collect::<Vec<*mut wasm_valtype_t>>();
|
||||
let out = Box::into_raw(Box::new(wasm_valtype_vec_t {
|
||||
size: valtypes.len(),
|
||||
data: valtypes.as_mut_ptr(),
|
||||
}));
|
||||
mem::forget(valtypes);
|
||||
out as *const _
|
||||
pub unsafe extern "C" fn wasm_functype_results(
|
||||
function_type: &wasm_functype_t,
|
||||
) -> *const wasm_valtype_vec_t {
|
||||
function_type.inner().results.as_ref() as *const _
|
||||
}
|
||||
|
||||
@@ -1,31 +1,41 @@
|
||||
use super::{
|
||||
wasm_externtype_t, wasm_mutability_enum, wasm_mutability_t, wasm_valtype_delete, wasm_valtype_t,
|
||||
wasm_externtype_t, wasm_mutability_enum, wasm_mutability_t, wasm_valtype_delete,
|
||||
wasm_valtype_t, WasmExternType,
|
||||
};
|
||||
use std::convert::TryInto;
|
||||
use wasmer::{ExternType, GlobalType};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct WasmGlobalType {
|
||||
pub(crate) global_type: GlobalType,
|
||||
}
|
||||
|
||||
impl WasmGlobalType {
|
||||
pub(crate) fn new(global_type: GlobalType) -> Self {
|
||||
Self { global_type }
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Debug)]
|
||||
#[repr(transparent)]
|
||||
pub struct wasm_globaltype_t {
|
||||
pub(crate) extern_: wasm_externtype_t,
|
||||
pub(crate) extern_type: wasm_externtype_t,
|
||||
}
|
||||
|
||||
impl wasm_globaltype_t {
|
||||
pub(crate) fn as_globaltype(&self) -> &GlobalType {
|
||||
if let ExternType::Global(ref g) = self.extern_.inner {
|
||||
g
|
||||
} else {
|
||||
unreachable!(
|
||||
"Data corruption detected: `wasm_globaltype_t` does not contain a `GlobalType`"
|
||||
);
|
||||
pub(crate) fn new(global_type: GlobalType) -> Self {
|
||||
Self {
|
||||
extern_type: wasm_externtype_t::new(ExternType::Global(global_type)),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn new(global_type: GlobalType) -> Self {
|
||||
Self {
|
||||
extern_: wasm_externtype_t {
|
||||
inner: ExternType::Global(global_type),
|
||||
},
|
||||
pub(crate) fn inner(&self) -> &WasmGlobalType {
|
||||
match &self.extern_type.inner {
|
||||
WasmExternType::Global(wasm_global_type) => &wasm_global_type,
|
||||
_ => {
|
||||
unreachable!("Data corruption: `wasm_globaltype_t` does not contain a global type")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -38,41 +48,35 @@ pub unsafe extern "C" fn wasm_globaltype_new(
|
||||
valtype: Option<Box<wasm_valtype_t>>,
|
||||
mutability: wasm_mutability_t,
|
||||
) -> Option<Box<wasm_globaltype_t>> {
|
||||
wasm_globaltype_new_inner(valtype?, mutability)
|
||||
let valtype = valtype?;
|
||||
let mutability: wasm_mutability_enum = mutability.try_into().ok()?;
|
||||
let global_type = Box::new(wasm_globaltype_t::new(GlobalType::new(
|
||||
(*valtype).into(),
|
||||
mutability.into(),
|
||||
)));
|
||||
|
||||
wasm_valtype_delete(Some(valtype));
|
||||
|
||||
Some(global_type)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasm_globaltype_delete(_globaltype: Option<Box<wasm_globaltype_t>>) {}
|
||||
|
||||
unsafe fn wasm_globaltype_new_inner(
|
||||
// own
|
||||
valtype: Box<wasm_valtype_t>,
|
||||
mutability: wasm_mutability_t,
|
||||
) -> Option<Box<wasm_globaltype_t>> {
|
||||
let me: wasm_mutability_enum = mutability.try_into().ok()?;
|
||||
let gd = Box::new(wasm_globaltype_t::new(GlobalType::new(
|
||||
(*valtype).into(),
|
||||
me.into(),
|
||||
)));
|
||||
wasm_valtype_delete(Some(valtype));
|
||||
|
||||
Some(gd)
|
||||
}
|
||||
pub unsafe extern "C" fn wasm_globaltype_delete(_global_type: Option<Box<wasm_globaltype_t>>) {}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasm_globaltype_mutability(
|
||||
globaltype: &wasm_globaltype_t,
|
||||
global_type: &wasm_globaltype_t,
|
||||
) -> wasm_mutability_t {
|
||||
let gt = globaltype.as_globaltype();
|
||||
wasm_mutability_enum::from(gt.mutability).into()
|
||||
wasm_mutability_enum::from(global_type.inner().global_type.mutability).into()
|
||||
}
|
||||
|
||||
// TODO: fix memory leak
|
||||
// this function leaks memory because the returned limits pointer is not owned
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasm_globaltype_content(
|
||||
globaltype: &wasm_globaltype_t,
|
||||
global_type: &wasm_globaltype_t,
|
||||
) -> *const wasm_valtype_t {
|
||||
let gt = globaltype.as_globaltype();
|
||||
Box::into_raw(Box::new(gt.ty.into()))
|
||||
let global_type = global_type.inner().global_type;
|
||||
|
||||
Box::into_raw(Box::new(global_type.ty.into()))
|
||||
}
|
||||
|
||||
@@ -1,49 +1,46 @@
|
||||
use super::wasm_externtype_t;
|
||||
use super::{wasm_externtype_t, WasmExternType};
|
||||
use wasmer::{ExternType, MemoryType, Pages};
|
||||
|
||||
// opaque type wrapping `MemoryType`
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct WasmMemoryType {
|
||||
pub(crate) memory_type: MemoryType,
|
||||
}
|
||||
|
||||
impl WasmMemoryType {
|
||||
pub(crate) fn new(memory_type: MemoryType) -> Self {
|
||||
Self { memory_type }
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Debug)]
|
||||
#[repr(transparent)]
|
||||
pub struct wasm_memorytype_t {
|
||||
pub(crate) extern_: wasm_externtype_t,
|
||||
pub(crate) extern_type: wasm_externtype_t,
|
||||
}
|
||||
|
||||
impl wasm_memorytype_t {
|
||||
pub(crate) fn as_memorytype(&self) -> &MemoryType {
|
||||
if let ExternType::Memory(ref mt) = self.extern_.inner {
|
||||
mt
|
||||
} else {
|
||||
unreachable!(
|
||||
"Data corruption detected: `wasm_memorytype_t` does not contain a `MemoryType`"
|
||||
);
|
||||
pub(crate) fn new(memory_type: MemoryType) -> Self {
|
||||
Self {
|
||||
extern_type: wasm_externtype_t::new(ExternType::Memory(memory_type)),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn new(memory_type: MemoryType) -> Self {
|
||||
Self {
|
||||
extern_: wasm_externtype_t {
|
||||
inner: ExternType::Memory(memory_type),
|
||||
},
|
||||
pub(crate) fn inner(&self) -> &WasmMemoryType {
|
||||
match &self.extern_type.inner {
|
||||
WasmExternType::Memory(wasm_memory_type) => &wasm_memory_type,
|
||||
_ => {
|
||||
unreachable!("Data corruption: `wasm_memorytype_t` does not contain a memory type")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wasm_declare_vec!(memorytype);
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[repr(C)]
|
||||
pub struct wasm_limits_t {
|
||||
pub(crate) min: u32,
|
||||
pub(crate) max: u32,
|
||||
}
|
||||
|
||||
const LIMITS_MAX_SENTINEL: u32 = u32::max_value();
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasm_memorytype_new(limits: &wasm_limits_t) -> Box<wasm_memorytype_t> {
|
||||
let min_pages = Pages(limits.min as _);
|
||||
// u32::max_value() is a sentinel value for no max specified
|
||||
let max_pages = if limits.max == LIMITS_MAX_SENTINEL {
|
||||
None
|
||||
} else {
|
||||
@@ -56,17 +53,29 @@ pub unsafe extern "C" fn wasm_memorytype_new(limits: &wasm_limits_t) -> Box<wasm
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasm_memorytype_delete(_memorytype: Option<Box<wasm_memorytype_t>>) {}
|
||||
pub unsafe extern "C" fn wasm_memorytype_delete(_memory_type: Option<Box<wasm_memorytype_t>>) {}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[repr(C)]
|
||||
pub struct wasm_limits_t {
|
||||
pub(crate) min: u32,
|
||||
pub(crate) max: u32,
|
||||
}
|
||||
|
||||
const LIMITS_MAX_SENTINEL: u32 = u32::max_value();
|
||||
|
||||
// TODO: fix memory leak
|
||||
// this function leaks memory because the returned limits pointer is not owned
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasm_memorytype_limits(mt: &wasm_memorytype_t) -> *const wasm_limits_t {
|
||||
let md = mt.as_memorytype();
|
||||
pub unsafe extern "C" fn wasm_memorytype_limits(
|
||||
memory_type: &wasm_memorytype_t,
|
||||
) -> *const wasm_limits_t {
|
||||
let memory_type = memory_type.inner().memory_type;
|
||||
|
||||
Box::into_raw(Box::new(wasm_limits_t {
|
||||
min: md.minimum.0 as _,
|
||||
max: md
|
||||
min: memory_type.minimum.0 as _,
|
||||
max: memory_type
|
||||
.maximum
|
||||
.map(|max| max.0 as _)
|
||||
.unwrap_or(LIMITS_MAX_SENTINEL),
|
||||
|
||||
@@ -1,68 +1,82 @@
|
||||
use super::{wasm_externtype_t, wasm_limits_t, wasm_valtype_delete, wasm_valtype_t};
|
||||
use super::{
|
||||
wasm_externtype_t, wasm_limits_t, wasm_valtype_delete, wasm_valtype_t, WasmExternType,
|
||||
};
|
||||
use wasmer::{ExternType, TableType};
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
pub type wasm_table_size_t = u32;
|
||||
|
||||
const LIMITS_MAX_SENTINEL: u32 = u32::max_value();
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct WasmTableType {
|
||||
pub(crate) table_type: TableType,
|
||||
}
|
||||
|
||||
impl WasmTableType {
|
||||
pub(crate) fn new(table_type: TableType) -> Self {
|
||||
Self { table_type }
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
#[derive(Clone, Debug)]
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
#[repr(transparent)]
|
||||
pub struct wasm_tabletype_t {
|
||||
pub(crate) extern_: wasm_externtype_t,
|
||||
pub(crate) extern_type: wasm_externtype_t,
|
||||
}
|
||||
|
||||
impl wasm_tabletype_t {
|
||||
pub(crate) fn new(table_type: TableType) -> Self {
|
||||
Self {
|
||||
extern_type: wasm_externtype_t::new(ExternType::Table(table_type)),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn inner(&self) -> &WasmTableType {
|
||||
match &self.extern_type.inner {
|
||||
WasmExternType::Table(wasm_table_type) => &wasm_table_type,
|
||||
_ => unreachable!("Data corruption: `wasm_tabletype_t` does not contain a table type"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wasm_declare_vec!(tabletype);
|
||||
|
||||
impl wasm_tabletype_t {
|
||||
pub(crate) fn as_tabletype(&self) -> &TableType {
|
||||
if let ExternType::Table(ref t) = self.extern_.inner {
|
||||
t
|
||||
} else {
|
||||
unreachable!(
|
||||
"Data corruption detected: `wasm_tabletype_t` does not contain a `TableType`"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const LIMITS_MAX_SENTINEL: u32 = u32::max_value();
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasm_tabletype_new(
|
||||
// own
|
||||
valtype: Box<wasm_valtype_t>,
|
||||
valtype: Option<Box<wasm_valtype_t>>,
|
||||
limits: &wasm_limits_t,
|
||||
) -> Box<wasm_tabletype_t> {
|
||||
) -> Option<Box<wasm_tabletype_t>> {
|
||||
let valtype = valtype?;
|
||||
let max_elements = if limits.max == LIMITS_MAX_SENTINEL {
|
||||
None
|
||||
} else {
|
||||
Some(limits.max as _)
|
||||
};
|
||||
let out = Box::new(wasm_tabletype_t {
|
||||
extern_: wasm_externtype_t {
|
||||
inner: ExternType::Table(TableType::new(
|
||||
let table_type = Box::new(wasm_tabletype_t::new(TableType::new(
|
||||
(*valtype).into(),
|
||||
limits.min as _,
|
||||
max_elements,
|
||||
)),
|
||||
},
|
||||
});
|
||||
)));
|
||||
|
||||
wasm_valtype_delete(Some(valtype));
|
||||
|
||||
out
|
||||
Some(table_type)
|
||||
}
|
||||
|
||||
// TODO: fix memory leak
|
||||
// this function leaks memory because the returned limits pointer is not owned
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasm_tabletype_limits(
|
||||
tabletype: &wasm_tabletype_t,
|
||||
table_type: &wasm_tabletype_t,
|
||||
) -> *const wasm_limits_t {
|
||||
let tt = tabletype.as_tabletype();
|
||||
let table_type = table_type.inner().table_type;
|
||||
|
||||
Box::into_raw(Box::new(wasm_limits_t {
|
||||
min: tt.minimum as _,
|
||||
max: tt.maximum.unwrap_or(LIMITS_MAX_SENTINEL),
|
||||
min: table_type.minimum as _,
|
||||
max: table_type.maximum.unwrap_or(LIMITS_MAX_SENTINEL),
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -70,12 +84,12 @@ pub unsafe extern "C" fn wasm_tabletype_limits(
|
||||
// this function leaks memory because the returned limits pointer is not owned
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasm_tabletype_element(
|
||||
tabletype: &wasm_tabletype_t,
|
||||
table_type: &wasm_tabletype_t,
|
||||
) -> *const wasm_valtype_t {
|
||||
let tt = tabletype.as_tabletype();
|
||||
let table_type = table_type.inner().table_type;
|
||||
|
||||
Box::into_raw(Box::new(tt.ty.into()))
|
||||
Box::into_raw(Box::new(table_type.ty.into()))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasm_tabletype_delete(_tabletype: Option<Box<wasm_tabletype_t>>) {}
|
||||
pub unsafe extern "C" fn wasm_tabletype_delete(_table_type: Option<Box<wasm_tabletype_t>>) {}
|
||||
|
||||
Reference in New Issue
Block a user