1use crate::r#ref::ExternRef;
2use crate::store::StoreOpaque;
3use crate::{AsContextMut, Func, ValType};
4use anyhow::{bail, Result};
5use std::ptr;
6use wasmtime_runtime::TableElement;
7
8pub use wasmtime_runtime::ValRaw;
9
10#[derive(Debug, Clone)]
13pub enum Val {
14 I32(i32),
18
19 I64(i64),
21
22 F32(u32),
27
28 F64(u64),
33
34 V128(u128),
36
37 FuncRef(Option<Func>),
42
43 ExternRef(Option<ExternRef>),
49}
50
51macro_rules! accessors {
52 ($bind:ident $(($variant:ident($ty:ty) $get:ident $unwrap:ident $cvt:expr))*) => ($(
53 #[inline]
56 pub fn $get(&self) -> Option<$ty> {
57 if let Val::$variant($bind) = self {
58 Some($cvt)
59 } else {
60 None
61 }
62 }
63
64 #[inline]
71 pub fn $unwrap(&self) -> $ty {
72 self.$get().expect(concat!("expected ", stringify!($ty)))
73 }
74 )*)
75}
76
77impl Val {
78 #[inline]
80 pub fn null() -> Val {
81 Val::ExternRef(None)
82 }
83
84 #[inline]
86 pub fn ty(&self) -> ValType {
87 match self {
88 Val::I32(_) => ValType::I32,
89 Val::I64(_) => ValType::I64,
90 Val::F32(_) => ValType::F32,
91 Val::F64(_) => ValType::F64,
92 Val::ExternRef(_) => ValType::ExternRef,
93 Val::FuncRef(_) => ValType::FuncRef,
94 Val::V128(_) => ValType::V128,
95 }
96 }
97
98 pub unsafe fn to_raw(&self, store: impl AsContextMut) -> ValRaw {
105 match self {
106 Val::I32(i) => ValRaw::i32(*i),
107 Val::I64(i) => ValRaw::i64(*i),
108 Val::F32(u) => ValRaw::f32(*u),
109 Val::F64(u) => ValRaw::f64(*u),
110 Val::V128(b) => ValRaw::v128(*b),
111 Val::ExternRef(e) => {
112 let externref = match e {
113 Some(e) => e.to_raw(store),
114 None => 0,
115 };
116 ValRaw::externref(externref)
117 }
118 Val::FuncRef(f) => {
119 let funcref = match f {
120 Some(f) => f.to_raw(store),
121 None => 0,
122 };
123 ValRaw::funcref(funcref)
124 }
125 }
126 }
127
128 pub unsafe fn from_raw(store: impl AsContextMut, raw: ValRaw, ty: ValType) -> Val {
136 match ty {
137 ValType::I32 => Val::I32(raw.get_i32()),
138 ValType::I64 => Val::I64(raw.get_i64()),
139 ValType::F32 => Val::F32(raw.get_f32()),
140 ValType::F64 => Val::F64(raw.get_f64()),
141 ValType::V128 => Val::V128(raw.get_v128()),
142 ValType::ExternRef => Val::ExternRef(ExternRef::from_raw(raw.get_externref())),
143 ValType::FuncRef => Val::FuncRef(Func::from_raw(store, raw.get_funcref())),
144 }
145 }
146
147 accessors! {
148 e
149 (I32(i32) i32 unwrap_i32 *e)
150 (I64(i64) i64 unwrap_i64 *e)
151 (F32(f32) f32 unwrap_f32 f32::from_bits(*e))
152 (F64(f64) f64 unwrap_f64 f64::from_bits(*e))
153 (FuncRef(Option<&Func>) funcref unwrap_funcref e.as_ref())
154 (V128(u128) v128 unwrap_v128 *e)
155 }
156
157 #[inline]
165 pub fn externref(&self) -> Option<Option<ExternRef>> {
166 match self {
167 Val::ExternRef(e) => Some(e.clone()),
168 _ => None,
169 }
170 }
171
172 #[inline]
183 pub fn unwrap_externref(&self) -> Option<ExternRef> {
184 self.externref().expect("expected externref")
185 }
186
187 pub(crate) fn into_table_element(
188 self,
189 store: &mut StoreOpaque,
190 ty: ValType,
191 ) -> Result<TableElement> {
192 match (self, ty) {
193 (Val::FuncRef(Some(f)), ValType::FuncRef) => {
194 if !f.comes_from_same_store(store) {
195 bail!("cross-`Store` values are not supported in tables");
196 }
197 Ok(TableElement::FuncRef(
198 f.caller_checked_anyfunc(store).as_ptr(),
199 ))
200 }
201 (Val::FuncRef(None), ValType::FuncRef) => Ok(TableElement::FuncRef(ptr::null_mut())),
202 (Val::ExternRef(Some(x)), ValType::ExternRef) => {
203 Ok(TableElement::ExternRef(Some(x.inner)))
204 }
205 (Val::ExternRef(None), ValType::ExternRef) => Ok(TableElement::ExternRef(None)),
206 _ => bail!("value does not match table element type"),
207 }
208 }
209
210 #[inline]
211 pub(crate) fn comes_from_same_store(&self, store: &StoreOpaque) -> bool {
212 match self {
213 Val::FuncRef(Some(f)) => f.comes_from_same_store(store),
214 Val::FuncRef(None) => true,
215
216 Val::I32(_)
220 | Val::I64(_)
221 | Val::F32(_)
222 | Val::F64(_)
223 | Val::V128(_)
224 | Val::ExternRef(_) => true,
225 }
226 }
227}
228
229impl From<i32> for Val {
230 #[inline]
231 fn from(val: i32) -> Val {
232 Val::I32(val)
233 }
234}
235
236impl From<i64> for Val {
237 #[inline]
238 fn from(val: i64) -> Val {
239 Val::I64(val)
240 }
241}
242
243impl From<f32> for Val {
244 #[inline]
245 fn from(val: f32) -> Val {
246 Val::F32(val.to_bits())
247 }
248}
249
250impl From<f64> for Val {
251 #[inline]
252 fn from(val: f64) -> Val {
253 Val::F64(val.to_bits())
254 }
255}
256
257impl From<ExternRef> for Val {
258 #[inline]
259 fn from(val: ExternRef) -> Val {
260 Val::ExternRef(Some(val))
261 }
262}
263
264impl From<Option<ExternRef>> for Val {
265 #[inline]
266 fn from(val: Option<ExternRef>) -> Val {
267 Val::ExternRef(val)
268 }
269}
270
271impl From<Option<Func>> for Val {
272 #[inline]
273 fn from(val: Option<Func>) -> Val {
274 Val::FuncRef(val)
275 }
276}
277
278impl From<Func> for Val {
279 #[inline]
280 fn from(val: Func) -> Val {
281 Val::FuncRef(Some(val))
282 }
283}
284
285impl From<u128> for Val {
286 #[inline]
287 fn from(val: u128) -> Val {
288 Val::V128(val)
289 }
290}