sp_wasm_interface_common/
lib.rs1#![cfg_attr(not(feature = "std"), no_std)]
21
22use sp_std::borrow::Cow;
23use core::{mem, marker::PhantomData};
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 { ptr, _marker: Default::default() }
196 }
197
198 pub fn offset(self, offset: u32) -> Option<Self> {
205 offset
206 .checked_mul(T::SIZE)
207 .and_then(|o| self.ptr.checked_add(o))
208 .map(|ptr| Self { ptr, _marker: Default::default() })
209 }
210
211 pub fn null() -> Self {
213 Self::new(0)
214 }
215
216 pub fn cast<R: PointerType>(self) -> Pointer<R> {
218 Pointer::new(self.ptr)
219 }
220}
221
222impl<T: PointerType> From<u32> for Pointer<T> {
223 fn from(ptr: u32) -> Self {
224 Pointer::new(ptr)
225 }
226}
227
228impl<T: PointerType> From<Pointer<T>> for u32 {
229 fn from(ptr: Pointer<T>) -> Self {
230 ptr.ptr
231 }
232}
233
234impl<T: PointerType> From<Pointer<T>> for u64 {
235 fn from(ptr: Pointer<T>) -> Self {
236 u64::from(ptr.ptr)
237 }
238}
239
240impl<T: PointerType> From<Pointer<T>> for usize {
241 fn from(ptr: Pointer<T>) -> Self {
242 ptr.ptr as _
243 }
244}
245
246impl<T: PointerType> IntoValue for Pointer<T> {
248 const VALUE_TYPE: ValueType = ValueType::I32;
249 fn into_value(self) -> Value {
250 Value::I32(self.ptr as _)
251 }
252}
253
254impl<T: PointerType> TryFromValue for Pointer<T> {
255 fn try_from_value(val: Value) -> Option<Self> {
256 match val {
257 Value::I32(val) => Some(Self::new(val as _)),
258 _ => None,
259 }
260 }
261}
262
263#[derive(Eq, PartialEq, Debug, Clone)]
265pub struct Signature {
266 pub args: Cow<'static, [ValueType]>,
268 pub return_value: Option<ValueType>,
270}
271
272impl Signature {
273 pub fn new<T: Into<Cow<'static, [ValueType]>>>(
275 args: T,
276 return_value: Option<ValueType>,
277 ) -> Self {
278 Self { args: args.into(), return_value }
279 }
280
281 pub fn new_with_args<T: Into<Cow<'static, [ValueType]>>>(args: T) -> Self {
283 Self { args: args.into(), return_value: None }
284 }
285}
286
287pub type WordSize = u32;
289
290pub type MemoryId = u32;
292
293pub type HostPointer = u64;
295
296#[derive(Clone, Copy, PartialEq, codec::Encode, codec::Decode, Debug)]
300pub enum ReturnValue {
301 Unit,
303 Value(Value),
305}
306
307impl From<Value> for ReturnValue {
308 fn from(v: Value) -> ReturnValue {
309 ReturnValue::Value(v)
310 }
311}
312
313impl ReturnValue {
314 pub const ENCODED_MAX_SIZE: usize = 10;
321}
322
323#[cfg(test)]
324mod tests {
325 use super::*;
326 use codec::Encode;
327
328 #[test]
329 fn pointer_offset_works() {
330 let ptr = Pointer::<u32>::null();
331
332 assert_eq!(ptr.offset(10).unwrap(), Pointer::new(40));
333 assert_eq!(ptr.offset(32).unwrap(), Pointer::new(128));
334
335 let ptr = Pointer::<u64>::null();
336
337 assert_eq!(ptr.offset(10).unwrap(), Pointer::new(80));
338 assert_eq!(ptr.offset(32).unwrap(), Pointer::new(256));
339 }
340
341 #[test]
342 fn return_value_encoded_max_size() {
343 let encoded = ReturnValue::Value(Value::I64(-1)).encode();
344 assert_eq!(encoded.len(), ReturnValue::ENCODED_MAX_SIZE);
345 }
346}