near_vm_types/
native.rs

1//! This module permits to create native functions
2//! easily in Rust, thanks to its advanced typing system.
3
4use crate::extern_ref::VMExternRef;
5use crate::lib::std::fmt;
6use crate::types::Type;
7use crate::values::{Value, WasmValueType};
8
9/// `NativeWasmType` represents a Wasm type that has a direct
10/// representation on the host (hence the “native” term).
11///
12/// It uses the Rust Type system to automatically detect the
13/// Wasm type associated with a native Rust type.
14///
15/// ```
16/// use near_vm_types::{NativeWasmType, Type};
17///
18/// let wasm_type = i32::WASM_TYPE;
19/// assert_eq!(wasm_type, Type::I32);
20/// ```
21///
22/// > Note: This strategy will be needed later to
23/// > automatically detect the signature of a Rust function.
24pub trait NativeWasmType: Sized {
25    /// The ABI for this type (i32, i64, f32, f64)
26    type Abi: Copy + fmt::Debug;
27
28    /// Type for this `NativeWasmType`.
29    const WASM_TYPE: Type;
30
31    #[doc(hidden)]
32    fn from_abi(abi: Self::Abi) -> Self;
33
34    #[doc(hidden)]
35    fn into_abi(self) -> Self::Abi;
36
37    /// Convert self to i128 binary representation.
38    fn to_binary(self) -> i128;
39
40    /// Convert self to a `Value`.
41    fn to_value<T: WasmValueType>(self) -> Value<T> {
42        let binary = self.to_binary();
43        // we need a store, we're just hoping we don't actually use it via funcref
44        // TODO(reftypes): we need an actual solution here
45        let hack = 3;
46
47        unsafe { Value::read_value_from(&hack, &binary, Self::WASM_TYPE) }
48    }
49
50    /// Convert to self from i128 binary representation.
51    fn from_binary(binary: i128) -> Self;
52}
53
54impl NativeWasmType for i32 {
55    const WASM_TYPE: Type = Type::I32;
56    type Abi = Self;
57
58    #[inline]
59    fn from_abi(abi: Self::Abi) -> Self {
60        abi
61    }
62
63    #[inline]
64    fn into_abi(self) -> Self::Abi {
65        self
66    }
67
68    #[inline]
69    fn to_binary(self) -> i128 {
70        self as _
71    }
72
73    #[inline]
74    fn from_binary(bits: i128) -> Self {
75        bits as _
76    }
77}
78
79impl NativeWasmType for i64 {
80    const WASM_TYPE: Type = Type::I64;
81    type Abi = Self;
82
83    #[inline]
84    fn from_abi(abi: Self::Abi) -> Self {
85        abi
86    }
87
88    #[inline]
89    fn into_abi(self) -> Self::Abi {
90        self
91    }
92
93    #[inline]
94    fn to_binary(self) -> i128 {
95        self as _
96    }
97
98    #[inline]
99    fn from_binary(bits: i128) -> Self {
100        bits as _
101    }
102}
103
104impl NativeWasmType for f32 {
105    const WASM_TYPE: Type = Type::F32;
106    type Abi = Self;
107
108    #[inline]
109    fn from_abi(abi: Self::Abi) -> Self {
110        abi
111    }
112
113    #[inline]
114    fn into_abi(self) -> Self::Abi {
115        self
116    }
117
118    #[inline]
119    fn to_binary(self) -> i128 {
120        self.to_bits() as _
121    }
122
123    #[inline]
124    fn from_binary(bits: i128) -> Self {
125        Self::from_bits(bits as _)
126    }
127}
128
129impl NativeWasmType for f64 {
130    const WASM_TYPE: Type = Type::F64;
131    type Abi = Self;
132
133    #[inline]
134    fn from_abi(abi: Self::Abi) -> Self {
135        abi
136    }
137
138    #[inline]
139    fn into_abi(self) -> Self::Abi {
140        self
141    }
142
143    #[inline]
144    fn to_binary(self) -> i128 {
145        self.to_bits() as _
146    }
147
148    #[inline]
149    fn from_binary(bits: i128) -> Self {
150        Self::from_bits(bits as _)
151    }
152}
153
154impl NativeWasmType for u128 {
155    const WASM_TYPE: Type = Type::V128;
156    type Abi = Self;
157
158    #[inline]
159    fn from_abi(abi: Self::Abi) -> Self {
160        abi
161    }
162
163    #[inline]
164    fn into_abi(self) -> Self::Abi {
165        self
166    }
167
168    #[inline]
169    fn to_binary(self) -> i128 {
170        self as _
171    }
172
173    #[inline]
174    fn from_binary(bits: i128) -> Self {
175        bits as _
176    }
177}
178
179impl NativeWasmType for VMExternRef {
180    const WASM_TYPE: Type = Type::ExternRef;
181    type Abi = Self;
182
183    #[inline]
184    fn from_abi(abi: Self::Abi) -> Self {
185        abi
186    }
187
188    #[inline]
189    fn into_abi(self) -> Self::Abi {
190        self
191    }
192
193    #[inline]
194    fn to_binary(self) -> i128 {
195        self.to_binary()
196    }
197
198    #[inline]
199    fn from_binary(bits: i128) -> Self {
200        // TODO(reftypes): ensure that the safety invariants are actually upheld here
201        unsafe { Self::from_binary(bits) }
202    }
203}
204
205#[cfg(test)]
206mod test_native_type {
207    use super::*;
208    use crate::types::Type;
209
210    #[test]
211    fn test_wasm_types() {
212        assert_eq!(i32::WASM_TYPE, Type::I32);
213        assert_eq!(i64::WASM_TYPE, Type::I64);
214        assert_eq!(f32::WASM_TYPE, Type::F32);
215        assert_eq!(f64::WASM_TYPE, Type::F64);
216        assert_eq!(u128::WASM_TYPE, Type::V128);
217    }
218
219    #[test]
220    fn test_roundtrip() {
221        assert_eq!(i32::from_binary(42i32.to_binary()), 42i32);
222        assert_eq!(i64::from_binary(42i64.to_binary()), 42i64);
223        assert_eq!(f32::from_binary(42f32.to_binary()), 42f32);
224        assert_eq!(f64::from_binary(42f64.to_binary()), 42f64);
225        assert_eq!(u128::from_binary(42u128.to_binary()), 42u128);
226    }
227}
228
229// pub trait IntegerAtomic
230// where
231//     Self: Sized
232// {
233//     type Primitive;
234
235//     fn add(&self, other: Self::Primitive) -> Self::Primitive;
236//     fn sub(&self, other: Self::Primitive) -> Self::Primitive;
237//     fn and(&self, other: Self::Primitive) -> Self::Primitive;
238//     fn or(&self, other: Self::Primitive) -> Self::Primitive;
239//     fn xor(&self, other: Self::Primitive) -> Self::Primitive;
240//     fn load(&self) -> Self::Primitive;
241//     fn store(&self, other: Self::Primitive) -> Self::Primitive;
242//     fn compare_exchange(&self, expected: Self::Primitive, new: Self::Primitive) -> Self::Primitive;
243//     fn swap(&self, other: Self::Primitive) -> Self::Primitive;
244// }
245
246/// Trait for a Value type. A Value type is a type that is always valid and may
247/// be safely copied.
248///
249/// That is, for all possible bit patterns a valid Value type can be constructed
250/// from those bits.
251///
252/// Concretely a `u32` is a Value type because every combination of 32 bits is
253/// a valid `u32`. However a `bool` is _not_ a Value type because any bit patterns
254/// other than `0` and `1` are invalid in Rust and may cause undefined behavior if
255/// a `bool` is constructed from those bytes.
256pub unsafe trait ValueType: Copy
257where
258    Self: Sized,
259{
260}
261
262macro_rules! impl_value_type_for {
263    ( $($type:ty),* ) => {
264        $(
265            unsafe impl ValueType for $type {}
266        )*
267    };
268}
269
270impl_value_type_for!(u8, i8, u16, i16, u32, i32, u64, i64, f32, f64);