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(u128),
21
22 RefExtern(ExternAddr),
23 RefFunc(FuncAddr),
24 RefNull(ValType),
25}
26
27impl WasmValue {
28 #[inline]
29 pub fn const_instr(&self) -> ConstInstruction {
30 match self {
31 Self::I32(i) => ConstInstruction::I32Const(*i),
32 Self::I64(i) => ConstInstruction::I64Const(*i),
33 Self::F32(i) => ConstInstruction::F32Const(*i),
34 Self::F64(i) => ConstInstruction::F64Const(*i),
35 Self::RefFunc(i) => ConstInstruction::RefFunc(*i),
36 Self::RefNull(ty) => ConstInstruction::RefNull(*ty),
37
38 _ => unimplemented!("no const_instr for {:?}", self),
40 }
41 }
42
43 #[inline]
45 pub fn default_for(ty: ValType) -> Self {
46 match ty {
47 ValType::I32 => Self::I32(0),
48 ValType::I64 => Self::I64(0),
49 ValType::F32 => Self::F32(0.0),
50 ValType::F64 => Self::F64(0.0),
51 ValType::V128 => Self::V128(0),
52 ValType::RefFunc => Self::RefNull(ValType::RefFunc),
53 ValType::RefExtern => Self::RefNull(ValType::RefExtern),
54 }
55 }
56
57 #[inline]
58 pub fn eq_loose(&self, other: &Self) -> bool {
59 match (self, other) {
60 (Self::I32(a), Self::I32(b)) => a == b,
61 (Self::I64(a), Self::I64(b)) => a == b,
62 (Self::RefNull(v), Self::RefNull(v2)) => v == v2,
63 (Self::RefExtern(addr), Self::RefExtern(addr2)) => addr == addr2,
64 (Self::RefFunc(addr), Self::RefFunc(addr2)) => addr == addr2,
65 (Self::F32(a), Self::F32(b)) => {
66 if a.is_nan() && b.is_nan() {
67 true } else {
69 a.to_bits() == b.to_bits()
70 }
71 }
72 (Self::F64(a), Self::F64(b)) => {
73 if a.is_nan() && b.is_nan() {
74 true } else {
76 a.to_bits() == b.to_bits()
77 }
78 }
79 _ => false,
80 }
81 }
82}
83
84#[cold]
85fn cold() {}
86
87impl Debug for WasmValue {
88 fn fmt(&self, f: &mut alloc::fmt::Formatter<'_>) -> alloc::fmt::Result {
89 match self {
90 WasmValue::I32(i) => write!(f, "i32({i})"),
91 WasmValue::I64(i) => write!(f, "i64({i})"),
92 WasmValue::F32(i) => write!(f, "f32({i})"),
93 WasmValue::F64(i) => write!(f, "f64({i})"),
94 WasmValue::V128(i) => write!(f, "v128({i:?})"),
95 WasmValue::RefExtern(addr) => write!(f, "ref.extern({addr:?})"),
96 WasmValue::RefFunc(addr) => write!(f, "ref.func({addr:?})"),
97 WasmValue::RefNull(ty) => write!(f, "ref.null({ty:?})"),
98 }
99 }
100}
101
102impl WasmValue {
103 #[inline]
105 pub fn val_type(&self) -> ValType {
106 match self {
107 Self::I32(_) => ValType::I32,
108 Self::I64(_) => ValType::I64,
109 Self::F32(_) => ValType::F32,
110 Self::F64(_) => ValType::F64,
111 Self::V128(_) => ValType::V128,
112 Self::RefExtern(_) => ValType::RefExtern,
113 Self::RefFunc(_) => ValType::RefFunc,
114 Self::RefNull(ty) => *ty,
115 }
116 }
117}
118
119#[derive(Debug, Clone, Copy, PartialEq, Eq)]
121#[cfg_attr(feature = "archive", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize), archive(check_bytes))]
122pub enum ValType {
123 I32,
125 I64,
127 F32,
129 F64,
131 V128,
133 RefFunc,
135 RefExtern,
137}
138
139impl ValType {
140 #[inline]
141 pub fn default_value(&self) -> WasmValue {
142 WasmValue::default_for(*self)
143 }
144
145 #[inline]
146 pub fn is_simd(&self) -> bool {
147 matches!(self, ValType::V128)
148 }
149}
150
151macro_rules! impl_conversion_for_wasmvalue {
152 ($($t:ty => $variant:ident),*) => {
153 $(
154 impl From<$t> for WasmValue {
156 #[inline]
157 fn from(i: $t) -> Self {
158 Self::$variant(i)
159 }
160 }
161
162 impl TryFrom<WasmValue> for $t {
164 type Error = ();
165
166 #[inline]
167 fn try_from(value: WasmValue) -> Result<Self, Self::Error> {
168 if let WasmValue::$variant(i) = value {
169 Ok(i)
170 } else {
171 cold();
172 Err(())
173 }
174 }
175 }
176 )*
177 }
178}
179
180impl_conversion_for_wasmvalue! { i32 => I32, i64 => I64, f32 => F32, f64 => F64, u128 => V128 }