1 use arbitrary::Arbitrary;
2 use std::mem::MaybeUninit;
3 use wasmtime::component::__internal::{
4     CanonicalAbiInfo, InstanceType, InterfaceType, LiftContext, LowerContext,
5 };
6 use wasmtime::component::{ComponentNamedList, ComponentType, Func, Lift, Lower, TypedFunc, Val};
7 use wasmtime::{AsContextMut, Config, Engine};
8 use wasmtime_environ::error::Result;
9 
10 pub trait TypedFuncExt<P, R> {
11     fn call_and_post_return(&self, store: impl AsContextMut<Data: Send>, params: P) -> Result<R>;
12 }
13 
14 impl<P, R> TypedFuncExt<P, R> for TypedFunc<P, R>
15 where
16     P: ComponentNamedList + Lower,
17     R: ComponentNamedList + Lift + Send + Sync + 'static,
18 {
19     fn call_and_post_return(
20         &self,
21         mut store: impl AsContextMut<Data: Send>,
22         params: P,
23     ) -> Result<R> {
24         let result = self.call(&mut store, params)?;
25         self.post_return(&mut store)?;
26         Ok(result)
27     }
28 }
29 
30 pub trait FuncExt {
31     fn call_and_post_return(
32         &self,
33         store: impl AsContextMut<Data: Send>,
34         params: &[Val],
35         results: &mut [Val],
36     ) -> Result<()>;
37 }
38 
39 impl FuncExt for Func {
40     fn call_and_post_return(
41         &self,
42         mut store: impl AsContextMut<Data: Send>,
43         params: &[Val],
44         results: &mut [Val],
45     ) -> Result<()> {
46         self.call(&mut store, params, results)?;
47         self.post_return(&mut store)?;
48         Ok(())
49     }
50 }
51 
52 pub fn config() -> Config {
53     drop(env_logger::try_init());
54 
55     let mut config = Config::new();
56     config.wasm_component_model(true);
57 
58     // When `WASMTIME_TEST_NO_HOG_MEMORY` is set it means we're in qemu. The
59     // component model tests create a disproportionate number of instances so
60     // try to cut down on virtual memory usage by avoiding 4G reservations.
61     if std::env::var("WASMTIME_TEST_NO_HOG_MEMORY").is_ok() {
62         config.memory_reservation(0);
63         config.memory_guard_size(0);
64     }
65     config
66 }
67 
68 pub fn engine() -> Engine {
69     Engine::new(&config()).unwrap()
70 }
71 
72 pub fn async_engine() -> Engine {
73     let mut config = config();
74     config.async_support(true);
75     Engine::new(&config).unwrap()
76 }
77 
78 /// Newtype wrapper for `f32` whose `PartialEq` impl considers NaNs equal to each other.
79 #[derive(Copy, Clone, Debug, Arbitrary)]
80 pub struct Float32(pub f32);
81 
82 /// Newtype wrapper for `f64` whose `PartialEq` impl considers NaNs equal to each other.
83 #[derive(Copy, Clone, Debug, Arbitrary)]
84 pub struct Float64(pub f64);
85 
86 macro_rules! forward_impls {
87     ($($a:ty => $b:ty,)*) => ($(
88         unsafe impl ComponentType for $a {
89             type Lower = <$b as ComponentType>::Lower;
90 
91             const ABI: CanonicalAbiInfo = <$b as ComponentType>::ABI;
92 
93             #[inline]
94             fn typecheck(ty: &InterfaceType, types: &InstanceType<'_>) -> Result<()> {
95                 <$b as ComponentType>::typecheck(ty, types)
96             }
97         }
98 
99         unsafe impl Lower for $a {
100             fn linear_lower_to_flat<U>(
101                 &self,
102                 cx: &mut LowerContext<'_, U>,
103                 ty: InterfaceType,
104                 dst: &mut MaybeUninit<Self::Lower>,
105             ) -> Result<()> {
106                 <$b as Lower>::linear_lower_to_flat(&self.0, cx, ty, dst)
107             }
108 
109             fn linear_lower_to_memory<U>(&self, cx: &mut LowerContext<'_, U>, ty: InterfaceType, offset: usize) -> Result<()> {
110                 <$b as Lower>::linear_lower_to_memory(&self.0, cx, ty, offset)
111             }
112         }
113 
114         unsafe impl Lift for $a {
115             fn linear_lift_from_flat(cx: &mut LiftContext<'_>, ty: InterfaceType, src: &Self::Lower) -> Result<Self> {
116                 Ok(Self(<$b as Lift>::linear_lift_from_flat(cx, ty, src)?))
117             }
118 
119             fn linear_lift_from_memory(cx: &mut LiftContext<'_>, ty: InterfaceType, bytes: &[u8]) -> Result<Self> {
120                 Ok(Self(<$b as Lift>::linear_lift_from_memory(cx, ty, bytes)?))
121             }
122         }
123 
124         impl PartialEq for $a {
125             fn eq(&self, other: &Self) -> bool {
126                 self.0 == other.0 || (self.0.is_nan() && other.0.is_nan())
127             }
128         }
129     )*)
130 }
131 
132 forward_impls! {
133     Float32 => f32,
134     Float64 => f64,
135 }
136