gsp_wasm_interface_common/
lib.rs1#![cfg_attr(not(feature = "std"), no_std)]
21
22use core::{marker::PhantomData, mem};
23use sp_std::borrow::Cow;
24
25pub mod util;
26
27#[cfg(feature = "wasmi")]
28pub use wasmi;
29
30#[cfg(feature = "wasmi")]
31pub mod wasmi_impl;
32
33#[derive(Copy, Clone, PartialEq, Debug, Eq)]
35pub enum ValueType {
36 I32,
38 I64,
40 F32,
42 F64,
44}
45
46impl From<ValueType> for u8 {
47 fn from(val: ValueType) -> u8 {
48 match val {
49 ValueType::I32 => 0,
50 ValueType::I64 => 1,
51 ValueType::F32 => 2,
52 ValueType::F64 => 3,
53 }
54 }
55}
56
57impl TryFrom<u8> for ValueType {
58 type Error = ();
59
60 fn try_from(val: u8) -> core::result::Result<ValueType, ()> {
61 match val {
62 0 => Ok(Self::I32),
63 1 => Ok(Self::I64),
64 2 => Ok(Self::F32),
65 3 => Ok(Self::F64),
66 _ => Err(()),
67 }
68 }
69}
70
71#[derive(PartialEq, Debug, Clone, Copy, codec::Encode, codec::Decode)]
73pub enum Value {
74 I32(i32),
76 I64(i64),
78 F32(u32),
82 F64(u64),
86}
87
88impl Value {
89 pub fn value_type(&self) -> ValueType {
91 match self {
92 Value::I32(_) => ValueType::I32,
93 Value::I64(_) => ValueType::I64,
94 Value::F32(_) => ValueType::F32,
95 Value::F64(_) => ValueType::F64,
96 }
97 }
98
99 pub fn as_i32(&self) -> Option<i32> {
101 match self {
102 Self::I32(val) => Some(*val),
103 _ => None,
104 }
105 }
106}
107
108pub trait IntoValue {
110 const VALUE_TYPE: ValueType;
112
113 fn into_value(self) -> Value;
115}
116
117pub trait TryFromValue: Sized {
119 fn try_from_value(val: Value) -> Option<Self>;
121}
122
123macro_rules! impl_into_and_from_value {
124 (
125 $(
126 $type:ty, $( < $gen:ident >, )? $value_variant:ident,
127 )*
128 ) => {
129 $(
130 impl $( <$gen> )? IntoValue for $type {
131 const VALUE_TYPE: ValueType = ValueType::$value_variant;
132 fn into_value(self) -> Value { Value::$value_variant(self as _) }
133 }
134
135 impl $( <$gen> )? TryFromValue for $type {
136 fn try_from_value(val: Value) -> Option<Self> {
137 match val {
138 Value::$value_variant(val) => Some(val as _),
139 _ => None,
140 }
141 }
142 }
143 )*
144 }
145}
146
147impl_into_and_from_value! {
148 u8, I32,
149 u16, I32,
150 u32, I32,
151 u64, I64,
152 i8, I32,
153 i16, I32,
154 i32, I32,
155 i64, I64,
156}
157
158mod private {
161 pub trait Sealed {}
162
163 impl Sealed for u8 {}
164 impl Sealed for u16 {}
165 impl Sealed for u32 {}
166 impl Sealed for u64 {}
167
168 impl Sealed for i32 {}
169 impl Sealed for i64 {}
170}
171
172pub trait PointerType: Sized + private::Sealed {
176 const SIZE: u32 = mem::size_of::<Self>() as u32;
178}
179
180impl PointerType for u8 {}
181impl PointerType for u16 {}
182impl PointerType for u32 {}
183impl PointerType for u64 {}
184
185#[derive(Debug, PartialEq, Eq, Clone, Copy)]
187pub struct Pointer<T: PointerType> {
188 ptr: u32,
189 _marker: PhantomData<T>,
190}
191
192impl<T: PointerType> Pointer<T> {
193 pub fn new(ptr: u32) -> Self {
195 Self {
196 ptr,
197 _marker: Default::default(),
198 }
199 }
200
201 pub fn offset(self, offset: u32) -> Option<Self> {
208 offset
209 .checked_mul(T::SIZE)
210 .and_then(|o| self.ptr.checked_add(o))
211 .map(|ptr| Self {
212 ptr,
213 _marker: Default::default(),
214 })
215 }
216
217 pub fn null() -> Self {
219 Self::new(0)
220 }
221
222 pub fn cast<R: PointerType>(self) -> Pointer<R> {
224 Pointer::new(self.ptr)
225 }
226}
227
228impl<T: PointerType> From<u32> for Pointer<T> {
229 fn from(ptr: u32) -> Self {
230 Pointer::new(ptr)
231 }
232}
233
234impl<T: PointerType> From<Pointer<T>> for u32 {
235 fn from(ptr: Pointer<T>) -> Self {
236 ptr.ptr
237 }
238}
239
240impl<T: PointerType> From<Pointer<T>> for u64 {
241 fn from(ptr: Pointer<T>) -> Self {
242 u64::from(ptr.ptr)
243 }
244}
245
246impl<T: PointerType> From<Pointer<T>> for usize {
247 fn from(ptr: Pointer<T>) -> Self {
248 ptr.ptr as _
249 }
250}
251
252impl<T: PointerType> IntoValue for Pointer<T> {
253 const VALUE_TYPE: ValueType = ValueType::I32;
254 fn into_value(self) -> Value {
255 Value::I32(self.ptr as _)
256 }
257}
258
259impl<T: PointerType> TryFromValue for Pointer<T> {
260 fn try_from_value(val: Value) -> Option<Self> {
261 match val {
262 Value::I32(val) => Some(Self::new(val as _)),
263 _ => None,
264 }
265 }
266}
267
268#[derive(Eq, PartialEq, Debug, Clone)]
270pub struct Signature {
271 pub args: Cow<'static, [ValueType]>,
273 pub return_value: Option<ValueType>,
275}
276
277impl Signature {
278 pub fn new<T: Into<Cow<'static, [ValueType]>>>(
280 args: T,
281 return_value: Option<ValueType>,
282 ) -> Self {
283 Self {
284 args: args.into(),
285 return_value,
286 }
287 }
288
289 pub fn new_with_args<T: Into<Cow<'static, [ValueType]>>>(args: T) -> Self {
291 Self {
292 args: args.into(),
293 return_value: None,
294 }
295 }
296}
297
298pub type WordSize = u32;
300
301pub type MemoryId = u32;
303
304pub type HostPointer = u64;
306
307#[derive(Clone, Copy, PartialEq, codec::Encode, codec::Decode, Debug)]
311pub enum ReturnValue {
312 Unit,
314 Value(Value),
316}
317
318impl From<Value> for ReturnValue {
319 fn from(v: Value) -> ReturnValue {
320 ReturnValue::Value(v)
321 }
322}
323
324impl ReturnValue {
325 pub const ENCODED_MAX_SIZE: usize = 10;
332}
333
334#[cfg(test)]
335mod tests {
336 use super::*;
337 use codec::Encode;
338
339 #[test]
340 fn pointer_offset_works() {
341 let ptr = Pointer::<u32>::null();
342
343 assert_eq!(ptr.offset(10).unwrap(), Pointer::new(40));
344 assert_eq!(ptr.offset(32).unwrap(), Pointer::new(128));
345
346 let ptr = Pointer::<u64>::null();
347
348 assert_eq!(ptr.offset(10).unwrap(), Pointer::new(80));
349 assert_eq!(ptr.offset(32).unwrap(), Pointer::new(256));
350 }
351
352 #[test]
353 fn return_value_encoded_max_size() {
354 let encoded = ReturnValue::Value(Value::I64(-1)).encode();
355 assert_eq!(encoded.len(), ReturnValue::ENCODED_MAX_SIZE);
356 }
357}