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