wai_bindgen_wasmer/
le.rs

1use crate::AllBytesValid;
2use std::cmp::Ordering;
3use std::fmt;
4use std::mem;
5use std::slice;
6
7/// Helper type representing a 1-byte-aligned little-endian value in memory.
8///
9/// This type is used in slice types for Wasmer host bindings. Guest types are
10/// not guaranteed to be either aligned or in the native endianness. This type
11/// wraps these types and provides explicit getters/setters to interact with the
12/// underlying value in a safe host-agnostic manner.
13#[repr(C, packed)]
14pub struct Le<T>(T);
15
16impl<T> Le<T>
17where
18    T: Endian,
19{
20    /// Creates a new `Le<T>` value where the internals are stored in a way
21    /// that's safe to copy into wasm linear memory.
22    pub fn new(t: T) -> Le<T> {
23        Le(t.into_le())
24    }
25
26    /// Reads the value stored in this `Le<T>`.
27    ///
28    /// This will perform a correct read even if the underlying memory is
29    /// unaligned, and it will also convert to the host's endianness for the
30    /// right representation of `T`.
31    pub fn get(&self) -> T {
32        self.0.from_le()
33    }
34
35    /// Writes the `val` to this slot.
36    ///
37    /// This will work correctly even if the underlying memory is unaligned and
38    /// it will also automatically convert the `val` provided to an endianness
39    /// appropriate for WebAssembly (little-endian).
40    pub fn set(&mut self, val: T) {
41        self.0 = val.into_le();
42    }
43
44    pub(crate) fn from_slice(bytes: &[u8]) -> &[Le<T>] {
45        // SAFETY: The invariants we uphold here are:
46        //
47        // * the lifetime of the input is the same as the output, so we're only
48        //   dealing with valid memory.
49        // * the alignment of the input is the same as the output (1)
50        // * the input isn't being truncated and we're consuming all of it (it
51        //   must be a multiple of the size of `Le<T>`)
52        // * all byte-patterns for `Le<T>` are valid. This is guaranteed by the
53        //   `AllBytesValid` supertrait of `Endian`.
54        unsafe {
55            assert_eq!(mem::align_of::<Le<T>>(), 1);
56            assert!(bytes.len() % mem::size_of::<Le<T>>() == 0);
57            fn all_bytes_valid<T: AllBytesValid>() {}
58            all_bytes_valid::<Le<T>>();
59
60            slice::from_raw_parts(
61                bytes.as_ptr().cast::<Le<T>>(),
62                bytes.len() / mem::size_of::<Le<T>>(),
63            )
64        }
65    }
66
67    pub(crate) fn from_slice_mut(bytes: &mut [u8]) -> &mut [Le<T>] {
68        // SAFETY: see `from_slice` above
69        //
70        // Note that both the input and the output are `mut`, helping to
71        // maintain the guarantee of uniqueness.
72        unsafe {
73            assert_eq!(mem::align_of::<Le<T>>(), 1);
74            assert!(bytes.len() % mem::size_of::<Le<T>>() == 0);
75            slice::from_raw_parts_mut(
76                bytes.as_mut_ptr().cast::<Le<T>>(),
77                bytes.len() / mem::size_of::<Le<T>>(),
78            )
79        }
80    }
81}
82
83impl<T: Copy> Clone for Le<T> {
84    fn clone(&self) -> Self {
85        *self
86    }
87}
88
89impl<T: Copy> Copy for Le<T> {}
90
91impl<T: Endian + PartialEq> PartialEq for Le<T> {
92    fn eq(&self, other: &Le<T>) -> bool {
93        self.get() == other.get()
94    }
95}
96
97impl<T: Endian + PartialEq> PartialEq<T> for Le<T> {
98    fn eq(&self, other: &T) -> bool {
99        self.get() == *other
100    }
101}
102
103impl<T: Endian + Eq> Eq for Le<T> {}
104
105impl<T: Endian + PartialOrd> PartialOrd for Le<T> {
106    fn partial_cmp(&self, other: &Le<T>) -> Option<Ordering> {
107        self.get().partial_cmp(&other.get())
108    }
109}
110
111impl<T: Endian + Ord> Ord for Le<T> {
112    fn cmp(&self, other: &Le<T>) -> Ordering {
113        self.get().cmp(&other.get())
114    }
115}
116
117impl<T: Endian + fmt::Debug> fmt::Debug for Le<T> {
118    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
119        self.get().fmt(f)
120    }
121}
122
123impl<T: Endian> From<T> for Le<T> {
124    fn from(t: T) -> Le<T> {
125        Le::new(t)
126    }
127}
128
129unsafe impl<T: AllBytesValid> AllBytesValid for Le<T> {}
130
131/// Trait used for the implementation of the `Le` type.
132pub trait Endian: AllBytesValid + Copy + Sized {
133    /// Converts this value and any aggregate fields (if any) into little-endian
134    /// byte order
135    fn into_le(self) -> Self;
136    /// Converts this value and any aggregate fields (if any) from
137    /// little-endian byte order
138    #[allow(clippy::wrong_self_convention)]
139    fn from_le(self) -> Self;
140}
141
142macro_rules! primitives {
143    ($($t:ident)*) => ($(
144        impl Endian for $t {
145            #[inline]
146            fn into_le(self) -> Self {
147                Self::from_ne_bytes(self.to_le_bytes())
148            }
149
150            #[inline]
151            fn from_le(self) -> Self {
152                Self::from_le_bytes(self.to_ne_bytes())
153            }
154        }
155    )*)
156}
157
158primitives! {
159    u8 i8
160    u16 i16
161    u32 i32
162    u64 i64
163    f32 f64
164}
165
166#[allow(clippy::unused_unit)]
167macro_rules! tuples {
168    ($(($($t:ident)*))*) => ($(
169        #[allow(non_snake_case)]
170        impl <$($t:Endian,)*> Endian for ($($t,)*) {
171            #[allow(clippy::unused_unit)]
172            fn into_le(self) -> Self {
173                let ($($t,)*) = self;
174                // Needed for single element "tuples".
175                ($($t.into_le(),)*)
176            }
177
178            #[allow(clippy::unused_unit)]
179            fn from_le(self) -> Self {
180                let ($($t,)*) = self;
181                // Needed for single element "tuples".
182                ($($t.from_le(),)*)
183            }
184        }
185    )*)
186}
187
188tuples! {
189    ()
190    (T1)
191    (T1 T2)
192    (T1 T2 T3)
193    (T1 T2 T3 T4)
194    (T1 T2 T3 T4 T5)
195    (T1 T2 T3 T4 T5 T6)
196    (T1 T2 T3 T4 T5 T6 T7)
197    (T1 T2 T3 T4 T5 T6 T7 T8)
198    (T1 T2 T3 T4 T5 T6 T7 T8 T9)
199    (T1 T2 T3 T4 T5 T6 T7 T8 T9 T10)
200}