wain_exec/
value.rs

1use std::convert::{TryFrom, TryInto};
2use std::fmt;
3use std::mem::size_of;
4use std::ops;
5use wain_ast::ValType;
6
7#[cfg_attr(test, derive(Debug))]
8#[derive(Clone, PartialEq)]
9pub enum Value {
10    I32(i32),
11    I64(i64),
12    F32(f32),
13    F64(f64),
14}
15
16impl Value {
17    pub fn valtype(&self) -> ValType {
18        match self {
19            Value::I32(_) => ValType::I32,
20            Value::I64(_) => ValType::I64,
21            Value::F32(_) => ValType::F32,
22            Value::F64(_) => ValType::F64,
23        }
24    }
25}
26
27macro_rules! impl_from_values {
28    ($($ty:ty => $variant:ident),*) => {
29        $(
30            impl From<$ty> for Value {
31                fn from(v: $ty) -> Value {
32                    Value::$variant(v)
33                }
34            }
35        )*
36    };
37}
38impl_from_values!(i32 => I32, i64 => I64, f32 => F32, f64 => F64);
39
40impl fmt::Display for Value {
41    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
42        match self {
43            Value::I32(v) => write!(f, "{}i32", v),
44            Value::I64(v) => write!(f, "{}i64", v),
45            Value::F32(v) => write!(f, "{}f32", v),
46            Value::F64(v) => write!(f, "{}f64", v),
47        }
48    }
49}
50
51pub trait LittleEndian {
52    fn read(buf: &[u8], addr: usize) -> Self;
53    fn write(buf: &mut [u8], addr: usize, v: Self);
54}
55
56fn read_bytes<'a, A>(buf: &'a [u8], addr: usize) -> A
57where
58    A: TryFrom<&'a [u8]>,
59    A::Error: fmt::Debug,
60{
61    buf[addr..addr + size_of::<A>()]
62        .try_into()
63        .expect("read bytes for value")
64}
65
66// TODO: copy_from_slice is slower here. I need to investigate the reason
67#[allow(clippy::manual_memcpy)]
68fn write_bytes(buf: &mut [u8], addr: usize, bytes: &[u8]) {
69    for i in 0..bytes.len() {
70        buf[addr + i] = bytes[i];
71    }
72}
73
74macro_rules! impl_le_rw {
75    ($t:ty) => {
76        impl LittleEndian for $t {
77            fn read(buf: &[u8], addr: usize) -> Self {
78                <$t>::from_le_bytes(read_bytes(buf, addr))
79            }
80            fn write(buf: &mut [u8], addr: usize, v: Self) {
81                write_bytes(buf, addr, &v.to_le_bytes());
82            }
83        }
84    };
85}
86
87impl_le_rw!(i8);
88impl_le_rw!(i16);
89impl_le_rw!(i32);
90impl_le_rw!(i64);
91impl_le_rw!(f32);
92impl_le_rw!(f64);
93// unsigned integers for load/store instructions
94impl LittleEndian for u8 {
95    fn read(buf: &[u8], addr: usize) -> Self {
96        buf[addr]
97    }
98    fn write(buf: &mut [u8], addr: usize, v: Self) {
99        buf[addr] = v;
100    }
101}
102impl_le_rw!(u16);
103impl_le_rw!(u32);
104
105// Trait to handle f32 and f64 in the same way
106pub(crate) trait Float: Clone + Copy + PartialEq + PartialOrd {
107    type UInt: Copy + ops::BitOr<Output = Self::UInt> + ops::BitAnd<Output = Self::UInt>;
108    const ARITHMETIC_NAN: Self::UInt;
109    fn is_nan(self) -> bool;
110    fn min(self, other: Self) -> Self;
111    fn max(self, other: Self) -> Self;
112    fn to_bits(self) -> Self::UInt;
113    fn from_bits(_: Self::UInt) -> Self;
114    fn to_arithmetic_nan(self) -> Self {
115        Self::from_bits(self.to_bits() | Self::ARITHMETIC_NAN)
116    }
117}
118
119macro_rules! impl_float {
120    ($float:ty, $uint:ty) => {
121        impl Float for $float {
122            type UInt = $uint;
123            const ARITHMETIC_NAN: Self::UInt = 1 << <$float>::MANTISSA_DIGITS - 2;
124            fn is_nan(self) -> bool {
125                self.is_nan()
126            }
127            fn min(self, other: Self) -> Self {
128                self.min(other)
129            }
130            fn max(self, other: Self) -> Self {
131                self.max(other)
132            }
133            fn to_bits(self) -> Self::UInt {
134                self.to_bits()
135            }
136            fn from_bits(b: Self::UInt) -> Self {
137                Self::from_bits(b)
138            }
139        }
140    };
141}
142
143impl_float!(f32, u32);
144impl_float!(f64, u64);