use arbitrary::Arbitrary;
use std::mem::MaybeUninit;
use wasmtime::component::__internal::{
CanonicalAbiInfo, InstanceType, InterfaceType, LiftContext, LowerContext,
};
use wasmtime::component::{ComponentNamedList, ComponentType, Func, Lift, Lower, TypedFunc, Val};
use wasmtime::{AsContextMut, Config, Engine};
use wasmtime_environ::error::Result;
pub trait TypedFuncExt
{
fn call_and_post_return(&self, store: impl AsContextMut, params: P) -> Result;
}
impl TypedFuncExt
for TypedFunc
where
P: ComponentNamedList + Lower,
R: ComponentNamedList + Lift + Send + Sync + 'static,
{
fn call_and_post_return(
&self,
mut store: impl AsContextMut,
params: P,
) -> Result {
let result = self.call(&mut store, params)?;
self.post_return(&mut store)?;
Ok(result)
}
}
pub trait FuncExt {
fn call_and_post_return(
&self,
store: impl AsContextMut,
params: &[Val],
results: &mut [Val],
) -> Result<()>;
}
impl FuncExt for Func {
fn call_and_post_return(
&self,
mut store: impl AsContextMut,
params: &[Val],
results: &mut [Val],
) -> Result<()> {
self.call(&mut store, params, results)?;
self.post_return(&mut store)?;
Ok(())
}
}
pub fn config() -> Config {
drop(env_logger::try_init());
let mut config = Config::new();
config.wasm_component_model(true);
// When `WASMTIME_TEST_NO_HOG_MEMORY` is set it means we're in qemu. The
// component model tests create a disproportionate number of instances so
// try to cut down on virtual memory usage by avoiding 4G reservations.
if std::env::var("WASMTIME_TEST_NO_HOG_MEMORY").is_ok() {
config.memory_reservation(0);
config.memory_guard_size(0);
}
config
}
pub fn engine() -> Engine {
Engine::new(&config()).unwrap()
}
pub fn async_engine() -> Engine {
let mut config = config();
config.async_support(true);
Engine::new(&config).unwrap()
}
/// Newtype wrapper for `f32` whose `PartialEq` impl considers NaNs equal to each other.
#[derive(Copy, Clone, Debug, Arbitrary)]
pub struct Float32(pub f32);
/// Newtype wrapper for `f64` whose `PartialEq` impl considers NaNs equal to each other.
#[derive(Copy, Clone, Debug, Arbitrary)]
pub struct Float64(pub f64);
macro_rules! forward_impls {
($($a:ty => $b:ty,)*) => ($(
unsafe impl ComponentType for $a {
type Lower = <$b as ComponentType>::Lower;
const ABI: CanonicalAbiInfo = <$b as ComponentType>::ABI;
#[inline]
fn typecheck(ty: &InterfaceType, types: &InstanceType<'_>) -> Result<()> {
<$b as ComponentType>::typecheck(ty, types)
}
}
unsafe impl Lower for $a {
fn linear_lower_to_flat(
&self,
cx: &mut LowerContext<'_, U>,
ty: InterfaceType,
dst: &mut MaybeUninit,
) -> Result<()> {
<$b as Lower>::linear_lower_to_flat(&self.0, cx, ty, dst)
}
fn linear_lower_to_memory(&self, cx: &mut LowerContext<'_, U>, ty: InterfaceType, offset: usize) -> Result<()> {
<$b as Lower>::linear_lower_to_memory(&self.0, cx, ty, offset)
}
}
unsafe impl Lift for $a {
fn linear_lift_from_flat(cx: &mut LiftContext<'_>, ty: InterfaceType, src: &Self::Lower) -> Result {
Ok(Self(<$b as Lift>::linear_lift_from_flat(cx, ty, src)?))
}
fn linear_lift_from_memory(cx: &mut LiftContext<'_>, ty: InterfaceType, bytes: &[u8]) -> Result {
Ok(Self(<$b as Lift>::linear_lift_from_memory(cx, ty, bytes)?))
}
}
impl PartialEq for $a {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0 || (self.0.is_nan() && other.0.is_nan())
}
}
)*)
}
forward_impls! {
Float32 => f32,
Float64 => f64,
}