1use crate::extern_ref::ExternRef;
2use crate::lib::std::convert::TryFrom;
3use crate::lib::std::fmt;
4use crate::lib::std::ptr;
5use crate::lib::std::string::{String, ToString};
6use crate::types::Type;
7
8#[derive(Clone, PartialEq)]
11pub enum Value<T> {
12 I32(i32),
16
17 I64(i64),
21
22 F32(f32),
24
25 F64(f64),
27
28 ExternRef(ExternRef),
32
33 FuncRef(Option<T>),
35
36 V128(u128),
38}
39
40macro_rules! accessors {
41 ($bind:ident $(($variant:ident($ty:ty) $get:ident $unwrap:ident $cvt:expr))*) => ($(
42 pub fn $get(&self) -> Option<$ty> {
45 if let Self::$variant($bind) = self {
46 Some($cvt)
47 } else {
48 None
49 }
50 }
51
52 pub fn $unwrap(&self) -> $ty {
59 self.$get().expect(concat!("expected ", stringify!($ty)))
60 }
61 )*)
62}
63
64pub trait WasmValueType: std::fmt::Debug + 'static {
67 unsafe fn write_value_to(&self, p: *mut i128);
69
70 unsafe fn read_value_from(store: &dyn std::any::Any, p: *const i128) -> Self;
76}
77
78impl WasmValueType for () {
79 unsafe fn write_value_to(&self, _p: *mut i128) {}
80
81 unsafe fn read_value_from(_store: &dyn std::any::Any, _p: *const i128) -> Self {
82 ()
83 }
84}
85
86impl<T> Value<T>
87where
88 T: WasmValueType,
89{
90 pub fn null() -> Self {
92 Self::ExternRef(ExternRef::null())
93 }
94
95 pub fn ty(&self) -> Type {
97 match self {
98 Self::I32(_) => Type::I32,
99 Self::I64(_) => Type::I64,
100 Self::F32(_) => Type::F32,
101 Self::F64(_) => Type::F64,
102 Self::ExternRef(_) => Type::ExternRef,
103 Self::FuncRef(_) => Type::FuncRef,
104 Self::V128(_) => Type::V128,
105 }
106 }
107
108 pub unsafe fn write_value_to(&self, p: *mut i128) {
115 match self {
116 Self::I32(i) => ptr::write(p as *mut i32, *i),
117 Self::I64(i) => ptr::write(p as *mut i64, *i),
118 Self::F32(u) => ptr::write(p as *mut f32, *u),
119 Self::F64(u) => ptr::write(p as *mut f64, *u),
120 Self::V128(b) => ptr::write(p as *mut u128, *b),
121 Self::FuncRef(Some(b)) => T::write_value_to(b, p),
122 Self::FuncRef(None) => ptr::write(p as *mut usize, 0),
123 Self::ExternRef(extern_ref) => ptr::write(p as *mut ExternRef, extern_ref.clone()),
125 }
126 }
127
128 pub unsafe fn read_value_from(store: &dyn std::any::Any, p: *const i128, ty: Type) -> Self {
135 match ty {
136 Type::I32 => Self::I32(ptr::read(p as *const i32)),
137 Type::I64 => Self::I64(ptr::read(p as *const i64)),
138 Type::F32 => Self::F32(ptr::read(p as *const f32)),
139 Type::F64 => Self::F64(ptr::read(p as *const f64)),
140 Type::V128 => Self::V128(ptr::read(p as *const u128)),
141 Type::FuncRef => {
142 if (*(p as *const usize)) == 0 {
144 Self::FuncRef(None)
145 } else {
146 Self::FuncRef(Some(T::read_value_from(store, p)))
147 }
148 }
149 Type::ExternRef => {
150 let extern_ref = (&*(p as *const ExternRef)).clone();
151 Self::ExternRef(extern_ref)
152 }
153 }
154 }
155
156 accessors! {
157 e
158 (I32(i32) i32 unwrap_i32 *e)
159 (I64(i64) i64 unwrap_i64 *e)
160 (F32(f32) f32 unwrap_f32 *e)
161 (F64(f64) f64 unwrap_f64 *e)
162 (ExternRef(ExternRef) externref unwrap_externref e.clone())
163 (FuncRef(&Option<T>) funcref unwrap_funcref e)
164 (V128(u128) v128 unwrap_v128 *e)
165 }
166}
167
168impl<T> fmt::Debug for Value<T>
169where
170 T: WasmValueType,
171{
172 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
173 match self {
174 Self::I32(v) => write!(f, "I32({:?})", v),
175 Self::I64(v) => write!(f, "I64({:?})", v),
176 Self::F32(v) => write!(f, "F32({:?})", v),
177 Self::F64(v) => write!(f, "F64({:?})", v),
178 Self::ExternRef(v) => write!(f, "ExternRef({:?})", v),
179 Self::FuncRef(None) => write!(f, "Null FuncRef"),
180 Self::FuncRef(Some(v)) => write!(f, "FuncRef({:?})", v),
181 Self::V128(v) => write!(f, "V128({:?})", v),
182 }
183 }
184}
185
186impl<T> ToString for Value<T>
187where
188 T: WasmValueType,
189{
190 fn to_string(&self) -> String {
191 match self {
192 Self::I32(v) => v.to_string(),
193 Self::I64(v) => v.to_string(),
194 Self::F32(v) => v.to_string(),
195 Self::F64(v) => v.to_string(),
196 Self::ExternRef(_) => "externref".to_string(),
197 Self::FuncRef(_) => "funcref".to_string(),
198 Self::V128(v) => v.to_string(),
199 }
200 }
201}
202
203impl<T> From<i32> for Value<T>
204where
205 T: WasmValueType,
206{
207 fn from(val: i32) -> Self {
208 Self::I32(val)
209 }
210}
211
212impl<T> From<u32> for Value<T>
213where
214 T: WasmValueType,
215{
216 fn from(val: u32) -> Self {
217 Self::I32(val as i32)
219 }
220}
221
222impl<T> From<i64> for Value<T>
223where
224 T: WasmValueType,
225{
226 fn from(val: i64) -> Self {
227 Self::I64(val)
228 }
229}
230
231impl<T> From<u64> for Value<T>
232where
233 T: WasmValueType,
234{
235 fn from(val: u64) -> Self {
236 Self::I64(val as i64)
238 }
239}
240
241impl<T> From<f32> for Value<T>
242where
243 T: WasmValueType,
244{
245 fn from(val: f32) -> Self {
246 Self::F32(val)
247 }
248}
249
250impl<T> From<f64> for Value<T>
251where
252 T: WasmValueType,
253{
254 fn from(val: f64) -> Self {
255 Self::F64(val)
256 }
257}
258
259impl<T> From<ExternRef> for Value<T>
260where
261 T: WasmValueType,
262{
263 fn from(val: ExternRef) -> Self {
264 Self::ExternRef(val)
265 }
266}
267
268const NOT_I32: &str = "Value is not of Wasm type i32";
275const NOT_I64: &str = "Value is not of Wasm type i64";
276const NOT_F32: &str = "Value is not of Wasm type f32";
277const NOT_F64: &str = "Value is not of Wasm type f64";
278
279impl<T> TryFrom<Value<T>> for i32
280where
281 T: WasmValueType,
282{
283 type Error = &'static str;
284
285 fn try_from(value: Value<T>) -> Result<Self, Self::Error> {
286 value.i32().ok_or(NOT_I32)
287 }
288}
289
290impl<T> TryFrom<Value<T>> for u32
291where
292 T: WasmValueType,
293{
294 type Error = &'static str;
295
296 fn try_from(value: Value<T>) -> Result<Self, Self::Error> {
297 value.i32().ok_or(NOT_I32).map(|int| int as Self)
298 }
299}
300
301impl<T> TryFrom<Value<T>> for i64
302where
303 T: WasmValueType,
304{
305 type Error = &'static str;
306
307 fn try_from(value: Value<T>) -> Result<Self, Self::Error> {
308 value.i64().ok_or(NOT_I64)
309 }
310}
311
312impl<T> TryFrom<Value<T>> for u64
313where
314 T: WasmValueType,
315{
316 type Error = &'static str;
317
318 fn try_from(value: Value<T>) -> Result<Self, Self::Error> {
319 value.i64().ok_or(NOT_I64).map(|int| int as Self)
320 }
321}
322
323impl<T> TryFrom<Value<T>> for f32
324where
325 T: WasmValueType,
326{
327 type Error = &'static str;
328
329 fn try_from(value: Value<T>) -> Result<Self, Self::Error> {
330 value.f32().ok_or(NOT_F32)
331 }
332}
333
334impl<T> TryFrom<Value<T>> for f64
335where
336 T: WasmValueType,
337{
338 type Error = &'static str;
339
340 fn try_from(value: Value<T>) -> Result<Self, Self::Error> {
341 value.f64().ok_or(NOT_F64)
342 }
343}
344
345#[cfg(test)]
346mod tests {
347 use super::*;
348
349 #[test]
350 fn test_value_i32_from_u32() {
351 let bytes = [0x00, 0x00, 0x00, 0x00];
352 let v = Value::<()>::from(u32::from_be_bytes(bytes));
353 assert_eq!(v, Value::I32(i32::from_be_bytes(bytes)));
354
355 let bytes = [0x00, 0x00, 0x00, 0x01];
356 let v = Value::<()>::from(u32::from_be_bytes(bytes));
357 assert_eq!(v, Value::I32(i32::from_be_bytes(bytes)));
358
359 let bytes = [0xAA, 0xBB, 0xCC, 0xDD];
360 let v = Value::<()>::from(u32::from_be_bytes(bytes));
361 assert_eq!(v, Value::I32(i32::from_be_bytes(bytes)));
362
363 let bytes = [0xFF, 0xFF, 0xFF, 0xFF];
364 let v = Value::<()>::from(u32::from_be_bytes(bytes));
365 assert_eq!(v, Value::I32(i32::from_be_bytes(bytes)));
366 }
367
368 #[test]
369 fn test_value_i64_from_u64() {
370 let bytes = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
371 let v = Value::<()>::from(u64::from_be_bytes(bytes));
372 assert_eq!(v, Value::I64(i64::from_be_bytes(bytes)));
373
374 let bytes = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01];
375 let v = Value::<()>::from(u64::from_be_bytes(bytes));
376 assert_eq!(v, Value::I64(i64::from_be_bytes(bytes)));
377
378 let bytes = [0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x00, 0x11];
379 let v = Value::<()>::from(u64::from_be_bytes(bytes));
380 assert_eq!(v, Value::I64(i64::from_be_bytes(bytes)));
381
382 let bytes = [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF];
383 let v = Value::<()>::from(u64::from_be_bytes(bytes));
384 assert_eq!(v, Value::I64(i64::from_be_bytes(bytes)));
385 }
386
387 #[test]
388 fn convert_value_to_i32() {
389 let value = Value::<()>::I32(5678);
390 let result = i32::try_from(value);
391 assert_eq!(result.unwrap(), 5678);
392
393 let value = Value::<()>::from(u32::MAX);
394 let result = i32::try_from(value);
395 assert_eq!(result.unwrap(), -1);
396
397 let value = Value::<()>::V128(42);
398 let result = i32::try_from(value);
399 assert_eq!(result.unwrap_err(), "Value is not of Wasm type i32");
400 }
401
402 #[test]
403 fn convert_value_to_u32() {
404 let value = Value::<()>::from(u32::MAX);
405 let result = u32::try_from(value);
406 assert_eq!(result.unwrap(), u32::MAX);
407
408 let value = Value::<()>::I32(-1);
409 let result = u32::try_from(value);
410 assert_eq!(result.unwrap(), u32::MAX);
411
412 let value = Value::<()>::V128(42);
413 let result = u32::try_from(value);
414 assert_eq!(result.unwrap_err(), "Value is not of Wasm type i32");
415 }
416
417 #[test]
418 fn convert_value_to_i64() {
419 let value = Value::<()>::I64(5678);
420 let result = i64::try_from(value);
421 assert_eq!(result.unwrap(), 5678);
422
423 let value = Value::<()>::from(u64::MAX);
424 let result = i64::try_from(value);
425 assert_eq!(result.unwrap(), -1);
426
427 let value = Value::<()>::V128(42);
428 let result = i64::try_from(value);
429 assert_eq!(result.unwrap_err(), "Value is not of Wasm type i64");
430 }
431
432 #[test]
433 fn convert_value_to_u64() {
434 let value = Value::<()>::from(u64::MAX);
435 let result = u64::try_from(value);
436 assert_eq!(result.unwrap(), u64::MAX);
437
438 let value = Value::<()>::I64(-1);
439 let result = u64::try_from(value);
440 assert_eq!(result.unwrap(), u64::MAX);
441
442 let value = Value::<()>::V128(42);
443 let result = u64::try_from(value);
444 assert_eq!(result.unwrap_err(), "Value is not of Wasm type i64");
445 }
446
447 #[test]
448 fn convert_value_to_f32() {
449 let value = Value::<()>::F32(1.234);
450 let result = f32::try_from(value);
451 assert_eq!(result.unwrap(), 1.234);
452
453 let value = Value::<()>::V128(42);
454 let result = f32::try_from(value);
455 assert_eq!(result.unwrap_err(), "Value is not of Wasm type f32");
456
457 let value = Value::<()>::F64(1.234);
458 let result = f32::try_from(value);
459 assert_eq!(result.unwrap_err(), "Value is not of Wasm type f32");
460 }
461
462 #[test]
463 fn convert_value_to_f64() {
464 let value = Value::<()>::F64(1.234);
465 let result = f64::try_from(value);
466 assert_eq!(result.unwrap(), 1.234);
467
468 let value = Value::<()>::V128(42);
469 let result = f64::try_from(value);
470 assert_eq!(result.unwrap_err(), "Value is not of Wasm type f64");
471
472 let value = Value::<()>::F32(1.234);
473 let result = f64::try_from(value);
474 assert_eq!(result.unwrap_err(), "Value is not of Wasm type f64");
475 }
476}