1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
use core::{fmt, marker::PhantomData, mem::MaybeUninit};

/// Raw representation of a WebAssembly value.
///
/// In most cases you will want to use the type-safe `Value` wrapper instead.
#[allow(missing_docs)]
#[repr(C)]
#[derive(Copy, Clone)]
pub union RawValue {
    pub i32: i32,
    pub i64: i64,
    pub u32: u32,
    pub u64: u64,
    pub f32: f32,
    pub f64: f64,
    pub i128: i128,
    pub u128: u128,
    pub funcref: usize,
    pub externref: usize,
    pub bytes: [u8; 16],
}

impl From<i32> for RawValue {
    fn from(value: i32) -> Self {
        Self { i32: value }
    }
}

impl From<i64> for RawValue {
    fn from(value: i64) -> Self {
        Self { i64: value }
    }
}

impl From<f32> for RawValue {
    fn from(value: f32) -> Self {
        Self { f32: value }
    }
}

impl From<f64> for RawValue {
    fn from(value: f64) -> Self {
        Self { f64: value }
    }
}

impl Default for RawValue {
    fn default() -> Self {
        Self { bytes: [0; 16] }
    }
}

impl fmt::Debug for RawValue {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("RawValue")
            .field("bytes", unsafe { &self.bytes })
            .finish()
    }
}

macro_rules! partial_eq {
    ($($t:ty => $f:tt),*) => ($(
        impl PartialEq<$t> for RawValue {
            fn eq(&self, o: &$t) -> bool {
                unsafe { self.$f == *o }
            }
        }
    )*)
}

partial_eq! {
    i32 => i32,
    u32 => u32,
    i64 => i64,
    u64 => u64,
    f32 => f32,
    f64 => f64,
    i128 => i128,
    u128 => u128
}

impl PartialEq for RawValue {
    fn eq(&self, o: &Self) -> bool {
        unsafe { self.u128 == o.u128 }
    }
}

/// Trait for a Value type. A Value type is a type that is always valid and may
/// be safely copied.
///
/// # Safety
///
/// To maintain safety, types which implement this trait must be valid for all
/// bit patterns. This means that it cannot contain enums, `bool`, references,
/// etc.
///
/// Concretely a `u32` is a Value type because every combination of 32 bits is
/// a valid `u32`. However a `bool` is _not_ a Value type because any bit patterns
/// other than `0` and `1` are invalid in Rust and may cause undefined behavior if
/// a `bool` is constructed from those bytes.
///
/// Additionally this trait has a method which zeros out any uninitializes bytes
/// prior to writing them to Wasm memory, which prevents information leaks into
/// the sandbox.
pub unsafe trait ValueType: Copy {
    /// This method is passed a byte slice which contains the byte
    /// representation of `self`. It must zero out any bytes which are
    /// uninitialized (e.g. padding bytes).
    fn zero_padding_bytes(&self, bytes: &mut [MaybeUninit<u8>]);
}

// Trivial implementations for primitive types and arrays of them.
macro_rules! primitives {
    ($($t:ident)*) => ($(
        unsafe impl ValueType for $t {
            #[inline]
            fn zero_padding_bytes(&self, _bytes: &mut [MaybeUninit<u8>]) {}
        }
        unsafe impl<const N: usize> ValueType for [$t; N] {
            #[inline]
            fn zero_padding_bytes(&self, _bytes: &mut [MaybeUninit<u8>]) {}
        }
    )*)
}
primitives! {
    bool
    i8 u8
    i16 u16
    i32 u32
    i64 u64
    i128 u128
    isize usize
    f32 f64
}

// This impl for PhantomData allows #[derive(ValueType)] to work with types
// that contain a PhantomData.
unsafe impl<T: ?Sized> ValueType for PhantomData<T> {
    #[inline]
    fn zero_padding_bytes(&self, _bytes: &mut [MaybeUninit<u8>]) {}
}