1 use crate::store::{AutoAssertNoGc, StoreOpaque};
2 use crate::{Result, ValRaw, ValType, WasmTy};
3 use core::cmp::Ordering;
4 use core::mem::MaybeUninit;
5 use core::{fmt, mem};
6 
7 /// Representation of a 128-bit vector type, `v128`, for WebAssembly.
8 ///
9 /// This type corresponds to the `v128` type in WebAssembly and can be used with
10 /// the [`TypedFunc`] API for example. This is additionally
11 /// the payload of [`Val::V128`](crate::Val).
12 ///
13 /// # Platform specifics
14 ///
15 /// This type can currently only be used on x86_64 and AArch64 with the
16 /// [`TypedFunc`] API. Rust does not have stable support on other platforms for
17 /// this type so invoking functions with `v128` parameters requires the
18 /// [`Func::call`](crate::Func::call) API (or perhaps
19 /// [`Func::call_unchecked`](crate::Func::call_unchecked).
20 ///
21 /// [`TypedFunc`]: crate::TypedFunc
22 #[derive(Copy, Clone)]
23 #[repr(transparent)]
24 pub struct V128(
25     // NB: represent this internally with a `u8` array so that `V128` does not
26     // have 16-byte alignment and force `Val`'s discriminant to be 16-bytes
27     // larger. These bytes are always in native-endian order.
28     [u8; mem::size_of::<u128>()],
29 );
30 
31 impl V128 {
32     /// Returns the representation of this `v128` as a 128-bit integer in Rust.
33     pub fn as_u128(&self) -> u128 {
34         u128::from_ne_bytes(self.0)
35     }
36 }
37 
38 /// Primary constructor of a `V128` type.
39 impl From<u128> for V128 {
40     fn from(val: u128) -> V128 {
41         Self(val.to_ne_bytes())
42     }
43 }
44 
45 impl From<V128> for u128 {
46     fn from(val: V128) -> u128 {
47         val.as_u128()
48     }
49 }
50 
51 impl fmt::Debug for V128 {
52     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
53         self.as_u128().fmt(f)
54     }
55 }
56 
57 impl PartialEq for V128 {
58     fn eq(&self, other: &V128) -> bool {
59         self.as_u128() == other.as_u128()
60     }
61 }
62 
63 impl Eq for V128 {}
64 
65 impl PartialOrd for V128 {
66     fn partial_cmp(&self, other: &V128) -> Option<Ordering> {
67         Some(self.cmp(other))
68     }
69 }
70 
71 impl Ord for V128 {
72     fn cmp(&self, other: &V128) -> Ordering {
73         self.as_u128().cmp(&other.as_u128())
74     }
75 }
76 
77 // Note that this trait is conditionally implemented which is intentional. See
78 // the documentation above in the `cfg_if!` for why this is conditional.
79 unsafe impl WasmTy for V128 {
80     #[inline]
81     fn valtype() -> ValType {
82         ValType::V128
83     }
84 
85     #[inline]
86     fn compatible_with_store(&self, _: &StoreOpaque) -> bool {
87         true
88     }
89 
90     fn dynamic_concrete_type_check(
91         &self,
92         _: &StoreOpaque,
93         _: bool,
94         _: &crate::HeapType,
95     ) -> anyhow::Result<()> {
96         unreachable!()
97     }
98 
99     #[inline]
100     fn store(self, _store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()> {
101         ptr.write(ValRaw::v128(self.as_u128()));
102         Ok(())
103     }
104 
105     #[inline]
106     unsafe fn load(_store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self {
107         V128::from(ptr.get_v128())
108     }
109 }
110