use wasmer_types::{NativeWasmType, RawValue, Type};
use crate::store::AsStoreRef;
use crate::vm::{VMExternRef, VMFuncRef};
use crate::{ExternRef, Function, TypedFunction};
use std::array::TryFromSliceError;
use std::convert::Infallible;
use std::convert::TryInto;
use std::error::Error;
use crate::store::AsStoreMut;
pub trait NativeWasmTypeInto: NativeWasmType + Sized {
#[doc(hidden)]
fn into_abi(self, store: &mut impl AsStoreMut) -> Self::Abi;
#[doc(hidden)]
unsafe fn from_abi(store: &mut impl AsStoreMut, abi: Self::Abi) -> Self;
fn into_raw(self, store: &mut impl AsStoreMut) -> RawValue;
unsafe fn from_raw(store: &mut impl AsStoreMut, raw: RawValue) -> Self;
}
impl NativeWasmTypeInto for i32 {
#[inline]
unsafe fn from_abi(_store: &mut impl AsStoreMut, abi: Self::Abi) -> Self {
abi
}
#[inline]
fn into_abi(self, _store: &mut impl AsStoreMut) -> Self::Abi {
self
}
#[inline]
fn into_raw(self, _store: &mut impl AsStoreMut) -> RawValue {
RawValue { i32: self }
}
#[inline]
unsafe fn from_raw(_store: &mut impl AsStoreMut, raw: RawValue) -> Self {
raw.i32
}
}
impl NativeWasmTypeInto for u32 {
#[inline]
unsafe fn from_abi(_store: &mut impl AsStoreMut, abi: Self::Abi) -> Self {
abi
}
#[inline]
fn into_abi(self, _store: &mut impl AsStoreMut) -> Self::Abi {
self
}
#[inline]
fn into_raw(self, _store: &mut impl AsStoreMut) -> RawValue {
RawValue { i32: self as _ }
}
#[inline]
unsafe fn from_raw(_store: &mut impl AsStoreMut, raw: RawValue) -> Self {
raw.i32 as _
}
}
impl NativeWasmTypeInto for i64 {
#[inline]
unsafe fn from_abi(_store: &mut impl AsStoreMut, abi: Self::Abi) -> Self {
abi
}
#[inline]
fn into_abi(self, _store: &mut impl AsStoreMut) -> Self::Abi {
self
}
#[inline]
fn into_raw(self, _store: &mut impl AsStoreMut) -> RawValue {
RawValue { i64: self }
}
#[inline]
unsafe fn from_raw(_store: &mut impl AsStoreMut, raw: RawValue) -> Self {
raw.i64
}
}
impl NativeWasmTypeInto for u64 {
#[inline]
unsafe fn from_abi(_store: &mut impl AsStoreMut, abi: Self::Abi) -> Self {
abi
}
#[inline]
fn into_abi(self, _store: &mut impl AsStoreMut) -> Self::Abi {
self
}
#[inline]
fn into_raw(self, _store: &mut impl AsStoreMut) -> RawValue {
RawValue { i64: self as _ }
}
#[inline]
unsafe fn from_raw(_store: &mut impl AsStoreMut, raw: RawValue) -> Self {
raw.i64 as _
}
}
impl NativeWasmTypeInto for f32 {
#[inline]
unsafe fn from_abi(_store: &mut impl AsStoreMut, abi: Self::Abi) -> Self {
abi
}
#[inline]
fn into_abi(self, _store: &mut impl AsStoreMut) -> Self::Abi {
self
}
#[inline]
fn into_raw(self, _store: &mut impl AsStoreMut) -> RawValue {
RawValue { f32: self }
}
#[inline]
unsafe fn from_raw(_store: &mut impl AsStoreMut, raw: RawValue) -> Self {
raw.f32
}
}
impl NativeWasmTypeInto for f64 {
#[inline]
unsafe fn from_abi(_store: &mut impl AsStoreMut, abi: Self::Abi) -> Self {
abi
}
#[inline]
fn into_abi(self, _store: &mut impl AsStoreMut) -> Self::Abi {
self
}
#[inline]
fn into_raw(self, _store: &mut impl AsStoreMut) -> RawValue {
RawValue { f64: self }
}
#[inline]
unsafe fn from_raw(_store: &mut impl AsStoreMut, raw: RawValue) -> Self {
raw.f64
}
}
impl NativeWasmTypeInto for u128 {
#[inline]
unsafe fn from_abi(_store: &mut impl AsStoreMut, abi: Self::Abi) -> Self {
abi
}
#[inline]
fn into_abi(self, _store: &mut impl AsStoreMut) -> Self::Abi {
self
}
#[inline]
fn into_raw(self, _store: &mut impl AsStoreMut) -> RawValue {
RawValue { u128: self }
}
#[inline]
unsafe fn from_raw(_store: &mut impl AsStoreMut, raw: RawValue) -> Self {
raw.u128
}
}
impl NativeWasmType for ExternRef {
const WASM_TYPE: Type = Type::ExternRef;
type Abi = usize;
}
impl NativeWasmTypeInto for Option<ExternRef> {
#[inline]
unsafe fn from_abi(store: &mut impl AsStoreMut, abi: Self::Abi) -> Self {
VMExternRef::from_raw(RawValue { externref: abi })
.map(|e| ExternRef::from_vm_externref(store, e))
}
#[inline]
fn into_abi(self, _store: &mut impl AsStoreMut) -> Self::Abi {
self.map_or(0, |e| unsafe { e.vm_externref().into_raw().externref })
}
#[inline]
fn into_raw(self, _store: &mut impl AsStoreMut) -> RawValue {
self.map_or(RawValue { externref: 0 }, |e| e.vm_externref().into_raw())
}
#[inline]
unsafe fn from_raw(store: &mut impl AsStoreMut, raw: RawValue) -> Self {
VMExternRef::from_raw(raw).map(|e| ExternRef::from_vm_externref(store, e))
}
}
impl<Args, Rets> From<TypedFunction<Args, Rets>> for Function
where
Args: WasmTypeList,
Rets: WasmTypeList,
{
fn from(other: TypedFunction<Args, Rets>) -> Self {
other.into_function()
}
}
impl NativeWasmType for Function {
const WASM_TYPE: Type = Type::FuncRef;
type Abi = usize;
}
impl NativeWasmTypeInto for Option<Function> {
#[inline]
unsafe fn from_abi(store: &mut impl AsStoreMut, abi: Self::Abi) -> Self {
VMFuncRef::from_raw(RawValue { funcref: abi }).map(|f| Function::from_vm_funcref(store, f))
}
#[inline]
fn into_abi(self, store: &mut impl AsStoreMut) -> Self::Abi {
self.map_or(0, |f| unsafe { f.vm_funcref(store).into_raw().externref })
}
#[inline]
fn into_raw(self, store: &mut impl AsStoreMut) -> RawValue {
self.map_or(RawValue { externref: 0 }, |e| {
e.vm_funcref(store).into_raw()
})
}
#[inline]
unsafe fn from_raw(store: &mut impl AsStoreMut, raw: RawValue) -> Self {
VMFuncRef::from_raw(raw).map(|f| Function::from_vm_funcref(store, f))
}
}
pub unsafe trait FromToNativeWasmType
where
Self: Sized,
{
type Native: NativeWasmTypeInto;
fn from_native(native: Self::Native) -> Self;
fn to_native(self) -> Self::Native;
fn is_from_store(&self, _store: &impl AsStoreRef) -> bool {
true
}
}
macro_rules! from_to_native_wasm_type {
( $( $type:ty => $native_type:ty ),* ) => {
$(
#[allow(clippy::use_self)]
unsafe impl FromToNativeWasmType for $type {
type Native = $native_type;
#[inline]
fn from_native(native: Self::Native) -> Self {
native as Self
}
#[inline]
fn to_native(self) -> Self::Native {
self as Self::Native
}
}
)*
};
}
macro_rules! from_to_native_wasm_type_same_size {
( $( $type:ty => $native_type:ty ),* ) => {
$(
#[allow(clippy::use_self)]
unsafe impl FromToNativeWasmType for $type {
type Native = $native_type;
#[inline]
fn from_native(native: Self::Native) -> Self {
Self::from_ne_bytes(Self::Native::to_ne_bytes(native))
}
#[inline]
fn to_native(self) -> Self::Native {
Self::Native::from_ne_bytes(Self::to_ne_bytes(self))
}
}
)*
};
}
from_to_native_wasm_type!(
i8 => i32,
u8 => i32,
i16 => i32,
u16 => i32
);
from_to_native_wasm_type_same_size!(
i32 => i32,
u32 => i32,
i64 => i64,
u64 => i64,
f32 => f32,
f64 => f64
);
unsafe impl FromToNativeWasmType for Option<ExternRef> {
type Native = Self;
fn to_native(self) -> Self::Native {
self
}
fn from_native(n: Self::Native) -> Self {
n
}
fn is_from_store(&self, store: &impl AsStoreRef) -> bool {
self.as_ref().map_or(true, |e| e.is_from_store(store))
}
}
unsafe impl FromToNativeWasmType for Option<Function> {
type Native = Self;
fn to_native(self) -> Self::Native {
self
}
fn from_native(n: Self::Native) -> Self {
n
}
fn is_from_store(&self, store: &impl AsStoreRef) -> bool {
self.as_ref().map_or(true, |f| f.is_from_store(store))
}
}
#[cfg(test)]
mod test_from_to_native_wasm_type {
use super::*;
#[test]
fn test_to_native() {
assert_eq!(7i8.to_native(), 7i32);
assert_eq!(7u8.to_native(), 7i32);
assert_eq!(7i16.to_native(), 7i32);
assert_eq!(7u16.to_native(), 7i32);
assert_eq!(u32::MAX.to_native(), -1);
}
#[test]
fn test_to_native_same_size() {
assert_eq!(7i32.to_native(), 7i32);
assert_eq!(7u32.to_native(), 7i32);
assert_eq!(7i64.to_native(), 7i64);
assert_eq!(7u64.to_native(), 7i64);
assert_eq!(7f32.to_native(), 7f32);
assert_eq!(7f64.to_native(), 7f64);
}
}
pub trait WasmTypeList
where
Self: Sized,
{
type CStruct;
type Array: AsMut<[RawValue]>;
fn size() -> u32;
unsafe fn from_array(store: &mut impl AsStoreMut, array: Self::Array) -> Self;
unsafe fn from_slice(
store: &mut impl AsStoreMut,
slice: &[RawValue],
) -> Result<Self, TryFromSliceError>;
unsafe fn into_array(self, store: &mut impl AsStoreMut) -> Self::Array;
fn empty_array() -> Self::Array;
unsafe fn from_c_struct(store: &mut impl AsStoreMut, c_struct: Self::CStruct) -> Self;
unsafe fn into_c_struct(self, store: &mut impl AsStoreMut) -> Self::CStruct;
unsafe fn write_c_struct_to_ptr(c_struct: Self::CStruct, ptr: *mut RawValue);
fn wasm_types() -> &'static [Type];
}
pub trait IntoResult<T>
where
T: WasmTypeList,
{
type Error: Error + Sync + Send + 'static;
fn into_result(self) -> Result<T, Self::Error>;
}
impl<T> IntoResult<T> for T
where
T: WasmTypeList,
{
type Error = Infallible;
fn into_result(self) -> Result<Self, Infallible> {
Ok(self)
}
}
impl<T, E> IntoResult<T> for Result<T, E>
where
T: WasmTypeList,
E: Error + Sync + Send + 'static,
{
type Error = E;
fn into_result(self) -> Self {
self
}
}
#[cfg(test)]
mod test_into_result {
use super::*;
use std::convert::Infallible;
#[test]
fn test_into_result_over_t() {
let x: i32 = 42;
let result_of_x: Result<i32, Infallible> = x.into_result();
assert_eq!(result_of_x.unwrap(), x);
}
#[test]
fn test_into_result_over_result() {
{
let x: Result<i32, Infallible> = Ok(42);
let result_of_x: Result<i32, Infallible> = x.into_result();
assert_eq!(result_of_x, x);
}
{
use std::{error, fmt};
#[derive(Debug, PartialEq)]
struct E;
impl fmt::Display for E {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(formatter, "E")
}
}
impl error::Error for E {}
let x: Result<Infallible, E> = Err(E);
let result_of_x: Result<Infallible, E> = x.into_result();
assert_eq!(result_of_x.unwrap_err(), E);
}
}
}
impl WasmTypeList for Infallible {
type CStruct = Self;
type Array = [RawValue; 0];
fn size() -> u32 {
0
}
unsafe fn from_array(_: &mut impl AsStoreMut, _: Self::Array) -> Self {
unreachable!()
}
unsafe fn from_slice(
_: &mut impl AsStoreMut,
_: &[RawValue],
) -> Result<Self, TryFromSliceError> {
unreachable!()
}
unsafe fn into_array(self, _: &mut impl AsStoreMut) -> Self::Array {
[]
}
fn empty_array() -> Self::Array {
[]
}
unsafe fn from_c_struct(_: &mut impl AsStoreMut, self_: Self::CStruct) -> Self {
self_
}
unsafe fn into_c_struct(self, _: &mut impl AsStoreMut) -> Self::CStruct {
self
}
unsafe fn write_c_struct_to_ptr(_: Self::CStruct, _: *mut RawValue) {}
fn wasm_types() -> &'static [Type] {
&[]
}
}
macro_rules! impl_wasmtypelist {
( [$c_struct_representation:ident]
$c_struct_name:ident,
$( $x:ident ),* ) => {
#[repr($c_struct_representation)]
pub struct $c_struct_name< $( $x ),* > ( $( <<$x as FromToNativeWasmType>::Native as NativeWasmType>::Abi ),* )
where
$( $x: FromToNativeWasmType ),*;
#[allow(unused_parens, dead_code)]
impl< $( $x ),* >
WasmTypeList
for
( $( $x ),* )
where
$( $x: FromToNativeWasmType ),*
{
type CStruct = $c_struct_name< $( $x ),* >;
type Array = [RawValue; count_idents!( $( $x ),* )];
fn size() -> u32 {
count_idents!( $( $x ),* ) as _
}
#[allow(unused_mut)]
#[allow(clippy::unused_unit)]
#[allow(clippy::missing_safety_doc)]
unsafe fn from_array(mut _store: &mut impl AsStoreMut, array: Self::Array) -> Self {
#[allow(non_snake_case)]
let [ $( $x ),* ] = array;
(
$(
FromToNativeWasmType::from_native(NativeWasmTypeInto::from_raw(_store, $x))
),*
)
}
#[allow(clippy::missing_safety_doc)]
unsafe fn from_slice(store: &mut impl AsStoreMut, slice: &[RawValue]) -> Result<Self, TryFromSliceError> {
Ok(Self::from_array(store, slice.try_into()?))
}
#[allow(unused_mut)]
#[allow(clippy::missing_safety_doc)]
unsafe fn into_array(self, mut _store: &mut impl AsStoreMut) -> Self::Array {
#[allow(non_snake_case)]
let ( $( $x ),* ) = self;
[
$(
FromToNativeWasmType::to_native($x).into_raw(_store)
),*
]
}
fn empty_array() -> Self::Array {
[RawValue { i32: 0 }; count_idents!( $( $x ),* )]
}
#[allow(unused_mut)]
#[allow(clippy::unused_unit)]
#[allow(clippy::missing_safety_doc)]
unsafe fn from_c_struct(mut _store: &mut impl AsStoreMut, c_struct: Self::CStruct) -> Self {
#[allow(non_snake_case)]
let $c_struct_name( $( $x ),* ) = c_struct;
(
$(
FromToNativeWasmType::from_native(NativeWasmTypeInto::from_abi(_store, $x))
),*
)
}
#[allow(unused_parens, non_snake_case, unused_mut)]
#[allow(clippy::missing_safety_doc)]
unsafe fn into_c_struct(self, mut _store: &mut impl AsStoreMut) -> Self::CStruct {
let ( $( $x ),* ) = self;
$c_struct_name(
$(
FromToNativeWasmType::to_native($x).into_abi(_store)
),*
)
}
#[allow(non_snake_case)]
unsafe fn write_c_struct_to_ptr(c_struct: Self::CStruct, _ptr: *mut RawValue) {
let $c_struct_name( $( $x ),* ) = c_struct;
let mut _n = 0;
$(
*_ptr.add(_n).cast() = $x;
_n += 1;
)*
}
fn wasm_types() -> &'static [Type] {
&[
$(
$x::Native::WASM_TYPE
),*
]
}
}
};
}
macro_rules! count_idents {
( $($idents:ident),* ) => {
{
#[allow(dead_code, non_camel_case_types)]
enum Idents { $( $idents, )* __CountIdentsLast }
const COUNT: usize = Idents::__CountIdentsLast as usize;
COUNT
}
};
}
impl_wasmtypelist!([C] S0,);
impl_wasmtypelist!([transparent] S1, A1);
impl_wasmtypelist!([C] S2, A1, A2);
impl_wasmtypelist!([C] S3, A1, A2, A3);
impl_wasmtypelist!([C] S4, A1, A2, A3, A4);
impl_wasmtypelist!([C] S5, A1, A2, A3, A4, A5);
impl_wasmtypelist!([C] S6, A1, A2, A3, A4, A5, A6);
impl_wasmtypelist!([C] S7, A1, A2, A3, A4, A5, A6, A7);
impl_wasmtypelist!([C] S8, A1, A2, A3, A4, A5, A6, A7, A8);
impl_wasmtypelist!([C] S9, A1, A2, A3, A4, A5, A6, A7, A8, A9);
impl_wasmtypelist!([C] S10, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10);
impl_wasmtypelist!([C] S11, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11);
impl_wasmtypelist!([C] S12, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12);
impl_wasmtypelist!([C] S13, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13);
impl_wasmtypelist!([C] S14, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14);
impl_wasmtypelist!([C] S15, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15);
impl_wasmtypelist!([C] S16, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16);
impl_wasmtypelist!([C] S17, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17);
impl_wasmtypelist!([C] S18, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18);
impl_wasmtypelist!([C] S19, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19);
impl_wasmtypelist!([C] S20, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20);
impl_wasmtypelist!([C] S21, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21);
impl_wasmtypelist!([C] S22, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22);
impl_wasmtypelist!([C] S23, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23);
impl_wasmtypelist!([C] S24, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24);
impl_wasmtypelist!([C] S25, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24, A25);
impl_wasmtypelist!([C] S26, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24, A25, A26);
#[cfg(test)]
mod test_wasm_type_list {
use super::*;
use wasmer_types::Type;
#[test]
fn test_empty_array() {
assert_eq!(<()>::empty_array().len(), 0);
assert_eq!(<i32>::empty_array().len(), 1);
assert_eq!(<(i32, i64)>::empty_array().len(), 2);
}
#[test]
fn test_wasm_types_for_uni_values() {
assert_eq!(<i32>::wasm_types(), [Type::I32]);
assert_eq!(<i64>::wasm_types(), [Type::I64]);
assert_eq!(<f32>::wasm_types(), [Type::F32]);
assert_eq!(<f64>::wasm_types(), [Type::F64]);
}
#[test]
fn test_wasm_types_for_multi_values() {
assert_eq!(<(i32, i32)>::wasm_types(), [Type::I32, Type::I32]);
assert_eq!(<(i64, i64)>::wasm_types(), [Type::I64, Type::I64]);
assert_eq!(<(f32, f32)>::wasm_types(), [Type::F32, Type::F32]);
assert_eq!(<(f64, f64)>::wasm_types(), [Type::F64, Type::F64]);
assert_eq!(
<(i32, i64, f32, f64)>::wasm_types(),
[Type::I32, Type::I64, Type::F32, Type::F64]
);
}
}
#[cfg(test)]
mod test_native_type {
use super::*;
use wasmer_types::Type;
#[test]
fn test_wasm_types() {
assert_eq!(i32::WASM_TYPE, Type::I32);
assert_eq!(i64::WASM_TYPE, Type::I64);
assert_eq!(f32::WASM_TYPE, Type::F32);
assert_eq!(f64::WASM_TYPE, Type::F64);
assert_eq!(u128::WASM_TYPE, Type::V128);
}
}