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#[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);
93impl 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
105pub(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);