1use core::{fmt, marker::PhantomData, mem::MaybeUninit};
2
3#[allow(missing_docs)]
7#[repr(C)]
8#[derive(Copy, Clone)]
9pub union RawValue {
10 pub i32: i32,
11 pub i64: i64,
12 pub u32: u32,
13 pub u64: u64,
14 pub f32: f32,
15 pub f64: f64,
16 pub i128: i128,
17 pub u128: u128,
18 pub funcref: usize,
19 pub externref: usize,
20 pub exnref: u32,
21 pub bytes: [u8; 16],
22}
23
24impl RawValue {
25 #[inline]
26 fn with_zeroed_bytes(f: impl FnOnce(&mut Self)) -> Self {
27 let mut raw = Self::default();
28 f(&mut raw);
29 raw
30 }
31}
32
33impl From<i32> for RawValue {
34 fn from(value: i32) -> Self {
35 Self::with_zeroed_bytes(|raw| raw.i32 = value)
36 }
37}
38
39impl From<i64> for RawValue {
40 fn from(value: i64) -> Self {
41 Self::with_zeroed_bytes(|raw| raw.i64 = value)
42 }
43}
44
45impl From<f32> for RawValue {
46 fn from(value: f32) -> Self {
47 Self::with_zeroed_bytes(|raw| raw.f32 = value)
48 }
49}
50
51impl From<f64> for RawValue {
52 fn from(value: f64) -> Self {
53 Self::with_zeroed_bytes(|raw| raw.f64 = value)
54 }
55}
56
57impl Default for RawValue {
58 fn default() -> Self {
59 Self { bytes: [0; 16] }
60 }
61}
62
63impl fmt::Debug for RawValue {
64 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
65 f.debug_struct("RawValue")
66 .field("bytes", unsafe { &self.bytes })
67 .finish()
68 }
69}
70
71macro_rules! partial_eq {
72 ($($t:ty => $f:tt),*) => ($(
73 impl PartialEq<$t> for RawValue {
74 fn eq(&self, o: &$t) -> bool {
75 unsafe { self.$f == *o }
76 }
77 }
78 )*)
79}
80
81partial_eq! {
82 i32 => i32,
83 u32 => u32,
84 i64 => i64,
85 u64 => u64,
86 f32 => f32,
87 f64 => f64,
88 i128 => i128,
89 u128 => u128
90}
91
92impl PartialEq for RawValue {
93 fn eq(&self, o: &Self) -> bool {
94 unsafe { self.u128 == o.u128 }
95 }
96}
97
98pub unsafe trait ValueType: Copy {
116 fn zero_padding_bytes(&self, bytes: &mut [MaybeUninit<u8>]);
120}
121
122macro_rules! primitives {
124 ($($t:ident)*) => ($(
125 unsafe impl ValueType for $t {
126 #[inline]
127 fn zero_padding_bytes(&self, _bytes: &mut [MaybeUninit<u8>]) {}
128 }
129 unsafe impl<const N: usize> ValueType for [$t; N] {
130 #[inline]
131 fn zero_padding_bytes(&self, _bytes: &mut [MaybeUninit<u8>]) {}
132 }
133 )*)
134}
135primitives! {
136 bool
137 i8 u8
138 i16 u16
139 i32 u32
140 i64 u64
141 i128 u128
142 isize usize
143 f32 f64
144}
145
146unsafe impl<T: ?Sized> ValueType for PhantomData<T> {
149 #[inline]
150 fn zero_padding_bytes(&self, _bytes: &mut [MaybeUninit<u8>]) {}
151}
152
153#[cfg(test)]
154mod tests {
155 use super::RawValue;
156
157 #[test]
158 fn raw_value_zero_initialized() {
159 #[cfg(target_endian = "little")]
160 {
161 assert_eq!(RawValue::from(123i32), 123i64);
162 assert_eq!(RawValue::from(0.0f32), 0i64);
163 assert_eq!(RawValue::from(0.0f32), 0u128);
164
165 const VAL: f64 = 123.456;
166 assert_eq!(
167 RawValue::from(VAL),
168 u128::from(u64::from_ne_bytes(VAL.to_ne_bytes()))
169 );
170 }
171 }
172}