1use core::fmt::Debug;
2
3use crate::{ConstInstruction, ExternAddr, FuncAddr};
4
5#[derive(Clone, Copy, PartialEq)]
9pub enum WasmValue {
10 I32(i32),
13 I64(i64),
15 F32(f32),
17 F64(f64),
19 V128(i128),
21 RefExtern(ExternRef),
22 RefFunc(FuncRef),
23}
24
25impl Debug for WasmValue {
26 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
27 match self {
28 Self::I32(i) => write!(f, "i32({i})"),
29 Self::I64(i) => write!(f, "i64({i})"),
30 Self::F32(i) => write!(f, "f32({i})"),
31 Self::F64(i) => write!(f, "f64({i})"),
32 Self::V128(i) => write!(f, "v128({i:?})"),
33 #[cfg(feature = "debug")]
34 Self::RefExtern(i) => write!(f, "ref({i:?})"),
35 #[cfg(feature = "debug")]
36 Self::RefFunc(i) => write!(f, "func({i:?})"),
37 #[cfg(not(feature = "debug"))]
38 Self::RefExtern(_) => write!(f, "ref()"),
39 #[cfg(not(feature = "debug"))]
40 Self::RefFunc(_) => write!(f, "func()"),
41 }
42 }
43}
44
45const NULL_REF: u32 = u32::MAX;
46
47#[derive(Clone, Copy, PartialEq, Eq)]
48pub struct ExternRef(u32);
49
50#[derive(Clone, Copy, PartialEq, Eq)]
51pub struct FuncRef(u32);
52
53#[cfg(feature = "debug")]
54impl Debug for ExternRef {
55 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
56 match self.addr() {
57 Some(addr) => write!(f, "extern({addr:?})"),
58 None => write!(f, "extern(null)"),
59 }
60 }
61}
62
63#[cfg(feature = "debug")]
64impl Debug for FuncRef {
65 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
66 match self.addr() {
67 Some(addr) => write!(f, "func({addr:?})"),
68 None => write!(f, "func(null)"),
69 }
70 }
71}
72
73impl FuncRef {
74 #[inline]
75 pub const fn new(addr: Option<FuncAddr>) -> Self {
77 match addr {
78 Some(addr) => Self(addr),
79 None => Self::null(),
80 }
81 }
82
83 #[inline]
84 pub const fn null() -> Self {
86 Self(NULL_REF)
87 }
88
89 #[inline]
90 pub const fn is_null(&self) -> bool {
92 self.0 == NULL_REF
93 }
94
95 #[inline]
96 pub const fn addr(&self) -> Option<FuncAddr> {
98 if self.is_null() { None } else { Some(self.0) }
99 }
100
101 #[inline]
102 #[doc(hidden)]
103 pub const fn from_raw(raw: u32) -> Self {
104 Self(raw)
105 }
106
107 #[inline]
108 #[doc(hidden)]
109 pub const fn raw(&self) -> u32 {
110 self.0
111 }
112}
113
114impl ExternRef {
115 #[inline]
116 pub const fn new(addr: Option<ExternAddr>) -> Self {
119 match addr {
120 Some(addr) => Self(addr),
121 None => Self::null(),
122 }
123 }
124
125 #[inline]
127 pub const fn null() -> Self {
128 Self(NULL_REF)
129 }
130
131 #[inline]
133 pub const fn is_null(&self) -> bool {
134 self.0 == NULL_REF
135 }
136
137 #[inline]
139 pub const fn addr(&self) -> Option<ExternAddr> {
140 if self.is_null() { None } else { Some(self.0) }
141 }
142
143 #[inline]
144 #[doc(hidden)]
145 pub const fn from_raw(raw: u32) -> Self {
146 Self(raw)
147 }
148
149 #[inline]
150 #[doc(hidden)]
151 pub const fn raw(&self) -> u32 {
152 self.0
153 }
154}
155
156impl WasmValue {
157 #[inline]
158 pub fn const_instr(&self) -> alloc::boxed::Box<[ConstInstruction]> {
160 alloc::boxed::Box::new([match self {
161 Self::I32(i) => ConstInstruction::I32Const(*i),
162 Self::I64(i) => ConstInstruction::I64Const(*i),
163 Self::F32(i) => ConstInstruction::F32Const(*i),
164 Self::F64(i) => ConstInstruction::F64Const(*i),
165 Self::V128(i) => ConstInstruction::V128Const(*i),
166 Self::RefFunc(i) => ConstInstruction::RefFunc(i.addr()),
167 Self::RefExtern(i) => ConstInstruction::RefExtern(i.addr()),
168 }])
169 }
170
171 #[inline]
172 pub const fn default_for(ty: WasmType) -> Self {
174 match ty {
175 WasmType::I32 => Self::I32(0),
176 WasmType::I64 => Self::I64(0),
177 WasmType::F32 => Self::F32(0.0),
178 WasmType::F64 => Self::F64(0.0),
179 WasmType::V128 => Self::V128(0),
180 WasmType::RefFunc => Self::RefFunc(FuncRef::null()),
181 WasmType::RefExtern => Self::RefExtern(ExternRef::null()),
182 }
183 }
184
185 #[inline]
186 pub fn eq_loose(&self, other: &Self) -> bool {
188 match (self, other) {
189 (Self::I32(a), Self::I32(b)) => a == b,
190 (Self::I64(a), Self::I64(b)) => a == b,
191 (Self::V128(a), Self::V128(b)) => {
192 let a_bytes = a.to_le_bytes();
193 let b_bytes = b.to_le_bytes();
194 a_bytes == b_bytes || Self::v128_nan_eq(a_bytes, b_bytes)
195 }
196 (Self::RefExtern(addr), Self::RefExtern(addr2)) => addr == addr2,
197 (Self::RefFunc(addr), Self::RefFunc(addr2)) => addr == addr2,
198 (Self::F32(a), Self::F32(b)) => {
199 if a.is_nan() && b.is_nan() {
200 true
201 } else {
202 a.to_bits() == b.to_bits()
203 }
204 }
205 (Self::F64(a), Self::F64(b)) => {
206 if a.is_nan() && b.is_nan() {
207 true
208 } else {
209 a.to_bits() == b.to_bits()
210 }
211 }
212 _ => false,
213 }
214 }
215
216 fn v128_nan_eq(a: [u8; 16], b: [u8; 16]) -> bool {
217 let a_f32x4: [f32; 4] = [
218 f32::from_le_bytes([a[0], a[1], a[2], a[3]]),
219 f32::from_le_bytes([a[4], a[5], a[6], a[7]]),
220 f32::from_le_bytes([a[8], a[9], a[10], a[11]]),
221 f32::from_le_bytes([a[12], a[13], a[14], a[15]]),
222 ];
223 let b_f32x4: [f32; 4] = [
224 f32::from_le_bytes([b[0], b[1], b[2], b[3]]),
225 f32::from_le_bytes([b[4], b[5], b[6], b[7]]),
226 f32::from_le_bytes([b[8], b[9], b[10], b[11]]),
227 f32::from_le_bytes([b[12], b[13], b[14], b[15]]),
228 ];
229
230 let all_nan_match = a_f32x4.iter().zip(b_f32x4.iter()).all(|(x, y)| {
231 if x.is_nan() && y.is_nan() {
232 true
233 } else if x.is_nan() || y.is_nan() {
234 false
235 } else {
236 x.to_bits() == y.to_bits()
237 }
238 });
239
240 if all_nan_match && a_f32x4.iter().any(|x| x.is_nan()) {
241 return true;
242 }
243
244 let a_f64x2: [f64; 2] = [
245 f64::from_le_bytes([a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7]]),
246 f64::from_le_bytes([a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15]]),
247 ];
248 let b_f64x2: [f64; 2] = [
249 f64::from_le_bytes([b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]]),
250 f64::from_le_bytes([b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15]]),
251 ];
252
253 a_f64x2.iter().zip(b_f64x2.iter()).all(|(x, y)| {
254 if x.is_nan() && y.is_nan() {
255 true
256 } else if x.is_nan() || y.is_nan() {
257 false
258 } else {
259 x.to_bits() == y.to_bits()
260 }
261 }) && a_f64x2.iter().any(|x| x.is_nan())
262 }
263
264 pub const fn as_i32(&self) -> Option<i32> {
266 match self {
267 Self::I32(i) => Some(*i),
268 _ => None,
269 }
270 }
271
272 pub const fn as_i64(&self) -> Option<i64> {
274 match self {
275 Self::I64(i) => Some(*i),
276 _ => None,
277 }
278 }
279
280 pub const fn as_f32(&self) -> Option<f32> {
282 match self {
283 Self::F32(i) => Some(*i),
284 _ => None,
285 }
286 }
287
288 pub const fn as_f64(&self) -> Option<f64> {
290 match self {
291 Self::F64(i) => Some(*i),
292 _ => None,
293 }
294 }
295
296 pub const fn as_v128(&self) -> Option<i128> {
298 match self {
299 Self::V128(i) => Some(*i),
300 _ => None,
301 }
302 }
303
304 pub const fn as_ref_extern(&self) -> Option<ExternRef> {
306 match self {
307 Self::RefExtern(ref_extern) => Some(*ref_extern),
308 _ => None,
309 }
310 }
311
312 pub const fn as_ref_func(&self) -> Option<FuncRef> {
314 match self {
315 Self::RefFunc(ref_func) => Some(*ref_func),
316 _ => None,
317 }
318 }
319}
320
321impl From<&WasmValue> for WasmType {
322 #[inline]
323 fn from(value: &WasmValue) -> Self {
324 match value {
325 WasmValue::I32(_) => WasmType::I32,
326 WasmValue::I64(_) => WasmType::I64,
327 WasmValue::F32(_) => WasmType::F32,
328 WasmValue::F64(_) => WasmType::F64,
329 WasmValue::V128(_) => WasmType::V128,
330 WasmValue::RefExtern(_) => WasmType::RefExtern,
331 WasmValue::RefFunc(_) => WasmType::RefFunc,
332 }
333 }
334}
335
336impl From<WasmValue> for WasmType {
337 #[inline]
338 fn from(value: WasmValue) -> Self {
339 Self::from(&value)
340 }
341}
342
343#[derive(Clone, Copy, PartialEq, Eq)]
345#[cfg_attr(feature = "debug", derive(Debug))]
346#[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))]
347pub enum WasmType {
348 I32,
350 I64,
352 F32,
354 F64,
356 V128,
358 RefFunc,
360 RefExtern,
362}
363
364impl WasmType {
365 #[inline]
366 pub const fn default_value(&self) -> WasmValue {
367 WasmValue::default_for(*self)
368 }
369
370 #[inline]
371 pub const fn is_simd(&self) -> bool {
372 matches!(self, Self::V128)
373 }
374}
375
376macro_rules! impl_conversion_for_wasmvalue {
377 ($($t:ty => $variant:ident),*) => {
378 $(
379 impl From<$t> for WasmValue {
380 #[inline]
381 fn from(i: $t) -> Self {
382 Self::$variant(i)
383 }
384 }
385
386 impl TryFrom<WasmValue> for $t {
387 type Error = ();
388
389 #[inline]
390 fn try_from(value: WasmValue) -> Result<Self, Self::Error> {
391 if let WasmValue::$variant(i) = value { Ok(i) } else { Err(()) }
392 }
393 }
394 )*
395 }
396}
397
398impl_conversion_for_wasmvalue! { i32 => I32, i64 => I64, f32 => F32, f64 => F64, i128 => V128, ExternRef => RefExtern, FuncRef => RefFunc }