sp_runtime_interface/
pass_by.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// 	http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18//! Provides the [`PassBy`] trait to simplify the implementation of the
19//! runtime interface traits for custom types.
20//!
21//! [`Codec`], [`Inner`] and [`Enum`] are the provided strategy implementations.
22
23use crate::{
24	util::{pack_ptr_and_len, unpack_ptr_and_len},
25	RIType,
26};
27
28#[cfg(feature = "std")]
29use crate::host::*;
30#[cfg(not(feature = "std"))]
31use crate::wasm::*;
32
33#[cfg(feature = "std")]
34use sp_wasm_interface::{FunctionContext, Pointer, Result};
35
36use core::marker::PhantomData;
37
38#[cfg(not(feature = "std"))]
39use alloc::vec::Vec;
40
41/// Derive macro for implementing [`PassBy`] with the [`Codec`] strategy.
42///
43/// This requires that the type implements [`Encode`](codec::Encode) and
44/// [`Decode`](codec::Decode) from `parity-scale-codec`.
45///
46/// # Example
47///
48/// ```
49/// # use sp_runtime_interface::pass_by::PassByCodec;
50/// # use codec::{Encode, Decode};
51/// #[derive(PassByCodec, Encode, Decode)]
52/// struct EncodableType {
53///     name: Vec<u8>,
54///     param: u32,
55/// }
56/// ```
57pub use sp_runtime_interface_proc_macro::PassByCodec;
58
59/// Derive macro for implementing [`PassBy`] with the [`Inner`] strategy.
60///
61/// Besides implementing [`PassBy`], this derive also implements the helper trait
62/// [`PassByInner`].
63///
64/// The type is required to be a struct with just one field. The field type needs to implement
65/// the required traits to pass it between the wasm and the native side. (See the runtime
66/// interface crate for more information about these traits.)
67///
68/// # Example
69///
70/// ```
71/// # use sp_runtime_interface::pass_by::PassByInner;
72/// #[derive(PassByInner)]
73/// struct Data([u8; 32]);
74/// ```
75///
76/// ```
77/// # use sp_runtime_interface::pass_by::PassByInner;
78/// #[derive(PassByInner)]
79/// struct Data {
80///     data: [u8; 32],
81/// }
82/// ```
83pub use sp_runtime_interface_proc_macro::PassByInner;
84
85/// Derive macro for implementing [`PassBy`] with the [`Enum`] strategy.
86///
87/// Besides implementing [`PassBy`], this derive also implements `TryFrom<u8>` and
88/// `From<Self> for u8` for the type.
89///
90/// The type is required to be an enum with only unit variants and at maximum `256` variants.
91/// Also it is required that the type implements `Copy`.
92///
93/// # Example
94///
95/// ```
96/// # use sp_runtime_interface::pass_by::PassByEnum;
97/// #[derive(PassByEnum, Copy, Clone)]
98/// enum Data {
99///     Okay,
100///     NotOkay,
101///     // This will not work with the derive.
102///     //Why(u32),
103/// }
104/// ```
105pub use sp_runtime_interface_proc_macro::PassByEnum;
106
107/// Something that should be passed between wasm and the host using the given strategy.
108///
109/// See [`Codec`], [`Inner`] or [`Enum`] for more information about the provided strategies.
110pub trait PassBy: Sized {
111	/// The strategy that should be used to pass the type.
112	type PassBy: PassByImpl<Self>;
113}
114
115/// Something that provides a strategy for passing a type between wasm and the host.
116///
117/// This trait exposes the same functionality as [`crate::host::IntoFFIValue`] and
118/// [`crate::host::FromFFIValue`] to delegate the implementation for a type to a different type.
119///
120/// This trait is used for the host implementation.
121#[cfg(feature = "std")]
122pub trait PassByImpl<T>: RIType {
123	/// Convert the given instance to the ffi value.
124	///
125	/// For more information see: [`crate::host::IntoFFIValue::into_ffi_value`]
126	fn into_ffi_value(instance: T, context: &mut dyn FunctionContext) -> Result<Self::FFIType>;
127
128	/// Create `T` from the given ffi value.
129	///
130	/// For more information see: [`crate::host::FromFFIValue::from_ffi_value`]
131	fn from_ffi_value(context: &mut dyn FunctionContext, arg: Self::FFIType) -> Result<T>;
132}
133
134/// Something that provides a strategy for passing a type between wasm and the host.
135///
136/// This trait exposes the same functionality as [`crate::wasm::IntoFFIValue`] and
137/// [`crate::wasm::FromFFIValue`] to delegate the implementation for a type to a different type.
138///
139/// This trait is used for the wasm implementation.
140#[cfg(not(feature = "std"))]
141pub trait PassByImpl<T>: RIType {
142	/// The owned rust type that is stored with the ffi value in [`crate::wasm::WrappedFFIValue`].
143	type Owned;
144
145	/// Convert the given `instance` into [`crate::wasm::WrappedFFIValue`].
146	///
147	/// For more information see: [`crate::wasm::IntoFFIValue::into_ffi_value`]
148	fn into_ffi_value(instance: &T) -> WrappedFFIValue<Self::FFIType, Self::Owned>;
149
150	/// Create `T` from the given ffi value.
151	///
152	/// For more information see: [`crate::wasm::FromFFIValue::from_ffi_value`]
153	fn from_ffi_value(arg: Self::FFIType) -> T;
154}
155
156impl<T: PassBy> RIType for T {
157	type FFIType = <T::PassBy as RIType>::FFIType;
158}
159
160#[cfg(feature = "std")]
161impl<T: PassBy> IntoFFIValue for T {
162	fn into_ffi_value(
163		self,
164		context: &mut dyn FunctionContext,
165	) -> Result<<T::PassBy as RIType>::FFIType> {
166		T::PassBy::into_ffi_value(self, context)
167	}
168}
169
170#[cfg(feature = "std")]
171impl<T: PassBy> FromFFIValue for T {
172	type SelfInstance = Self;
173
174	fn from_ffi_value(
175		context: &mut dyn FunctionContext,
176		arg: <T::PassBy as RIType>::FFIType,
177	) -> Result<Self> {
178		T::PassBy::from_ffi_value(context, arg)
179	}
180}
181
182#[cfg(not(feature = "std"))]
183impl<T: PassBy> IntoFFIValue for T {
184	type Owned = <T::PassBy as PassByImpl<T>>::Owned;
185
186	fn into_ffi_value(&self) -> WrappedFFIValue<<T::PassBy as RIType>::FFIType, Self::Owned> {
187		T::PassBy::into_ffi_value(self)
188	}
189}
190
191#[cfg(not(feature = "std"))]
192impl<T: PassBy> FromFFIValue for T {
193	fn from_ffi_value(arg: <T::PassBy as RIType>::FFIType) -> Self {
194		T::PassBy::from_ffi_value(arg)
195	}
196}
197
198/// The implementation of the pass by codec strategy. This strategy uses a SCALE encoded
199/// representation of the type between wasm and the host.
200///
201/// Use this type as associated type for [`PassBy`] to implement this strategy for a type.
202///
203/// This type expects the type that wants to implement this strategy as generic parameter.
204///
205/// [`PassByCodec`](derive.PassByCodec.html) is a derive macro to implement this strategy.
206///
207/// # Example
208/// ```
209/// # use sp_runtime_interface::pass_by::{PassBy, Codec};
210/// #[derive(codec::Encode, codec::Decode)]
211/// struct Test;
212///
213/// impl PassBy for Test {
214///     type PassBy = Codec<Self>;
215/// }
216/// ```
217pub struct Codec<T: codec::Codec>(PhantomData<T>);
218
219#[cfg(feature = "std")]
220impl<T: codec::Codec> PassByImpl<T> for Codec<T> {
221	fn into_ffi_value(instance: T, context: &mut dyn FunctionContext) -> Result<Self::FFIType> {
222		let vec = instance.encode();
223		let ptr = context.allocate_memory(vec.len() as u32)?;
224		context.write_memory(ptr, &vec)?;
225
226		Ok(pack_ptr_and_len(ptr.into(), vec.len() as u32))
227	}
228
229	fn from_ffi_value(context: &mut dyn FunctionContext, arg: Self::FFIType) -> Result<T> {
230		let (ptr, len) = unpack_ptr_and_len(arg);
231		let vec = context.read_memory(Pointer::new(ptr), len)?;
232		T::decode(&mut &vec[..]).map_err(|e| format!("Could not decode value from wasm: {}", e))
233	}
234}
235
236#[cfg(not(feature = "std"))]
237impl<T: codec::Codec> PassByImpl<T> for Codec<T> {
238	type Owned = Vec<u8>;
239
240	fn into_ffi_value(instance: &T) -> WrappedFFIValue<Self::FFIType, Self::Owned> {
241		let data = instance.encode();
242		let ffi_value = pack_ptr_and_len(data.as_ptr() as u32, data.len() as u32);
243		(ffi_value, data).into()
244	}
245
246	fn from_ffi_value(arg: Self::FFIType) -> T {
247		let (ptr, len) = unpack_ptr_and_len(arg);
248		let len = len as usize;
249
250		let encoded = if len == 0 {
251			bytes::Bytes::new()
252		} else {
253			bytes::Bytes::from(unsafe { Vec::from_raw_parts(ptr as *mut u8, len, len) })
254		};
255
256		codec::decode_from_bytes(encoded).expect("Host to wasm values are encoded correctly; qed")
257	}
258}
259
260/// The type is passed as `u64`.
261///
262/// The `u64` value is build by `length 32bit << 32 | pointer 32bit`
263///
264/// `Self` is encoded and the length and the pointer are taken from the encoded vector.
265impl<T: codec::Codec> RIType for Codec<T> {
266	type FFIType = u64;
267}
268
269/// Trait that needs to be implemented by a type that should be passed between wasm and the host,
270/// by using the inner type. See [`Inner`] for more information.
271pub trait PassByInner: Sized {
272	/// The inner type that is wrapped by `Self`.
273	type Inner: RIType;
274
275	/// Consumes `self` and returns the inner type.
276	fn into_inner(self) -> Self::Inner;
277
278	/// Returns the reference to the inner type.
279	fn inner(&self) -> &Self::Inner;
280
281	/// Construct `Self` from the given `inner`.
282	fn from_inner(inner: Self::Inner) -> Self;
283}
284
285/// The implementation of the pass by inner type strategy. The type that uses this strategy will be
286/// passed between wasm and the host by using the wrapped inner type. So, this strategy is only
287/// usable by newtype structs.
288///
289/// Use this type as associated type for [`PassBy`] to implement this strategy for a type. Besides
290/// that the `PassByInner` trait need to be implemented as well.
291///
292/// This type expects the type that wants to use this strategy as generic parameter `T` and the
293/// inner type as generic parameter `I`.
294///
295/// [`PassByInner`](derive.PassByInner.html) is a derive macro to implement this strategy.
296///
297/// # Example
298/// ```
299/// # use sp_runtime_interface::pass_by::{PassBy, Inner, PassByInner};
300/// struct Test([u8; 32]);
301///
302/// impl PassBy for Test {
303///     type PassBy = Inner<Self, [u8; 32]>;
304/// }
305///
306/// impl PassByInner for Test {
307///     type Inner = [u8; 32];
308///
309///     fn into_inner(self) -> [u8; 32] {
310///         self.0
311///     }
312///     fn inner(&self) -> &[u8; 32] {
313///         &self.0
314///     }
315///     fn from_inner(inner: [u8; 32]) -> Self {
316///         Self(inner)
317///     }
318/// }
319/// ```
320pub struct Inner<T: PassByInner<Inner = I>, I: RIType>(PhantomData<(T, I)>);
321
322#[cfg(feature = "std")]
323impl<T: PassByInner<Inner = I>, I: RIType> PassByImpl<T> for Inner<T, I>
324where
325	I: IntoFFIValue + FromFFIValue<SelfInstance = I>,
326{
327	fn into_ffi_value(instance: T, context: &mut dyn FunctionContext) -> Result<Self::FFIType> {
328		instance.into_inner().into_ffi_value(context)
329	}
330
331	fn from_ffi_value(context: &mut dyn FunctionContext, arg: Self::FFIType) -> Result<T> {
332		I::from_ffi_value(context, arg).map(T::from_inner)
333	}
334}
335
336#[cfg(not(feature = "std"))]
337impl<T: PassByInner<Inner = I>, I: RIType> PassByImpl<T> for Inner<T, I>
338where
339	I: IntoFFIValue + FromFFIValue,
340{
341	type Owned = I::Owned;
342
343	fn into_ffi_value(instance: &T) -> WrappedFFIValue<Self::FFIType, Self::Owned> {
344		instance.inner().into_ffi_value()
345	}
346
347	fn from_ffi_value(arg: Self::FFIType) -> T {
348		T::from_inner(I::from_ffi_value(arg))
349	}
350}
351
352/// The type is passed as the inner type.
353impl<T: PassByInner<Inner = I>, I: RIType> RIType for Inner<T, I> {
354	type FFIType = I::FFIType;
355}
356
357/// The implementation of the pass by enum strategy. This strategy uses an `u8` internally to pass
358/// the enum between wasm and the host. So, this strategy only supports enums with unit variants.
359///
360/// Use this type as associated type for [`PassBy`] to implement this strategy for a type.
361///
362/// This type expects the type that wants to implement this strategy as generic parameter. Besides
363/// that the type needs to implement `TryFrom<u8>` and `From<Self> for u8`.
364///
365/// [`PassByEnum`](derive.PassByEnum.html) is a derive macro to implement this strategy.
366///
367/// # Example
368/// ```
369/// # use sp_runtime_interface::pass_by::{PassBy, Enum};
370/// #[derive(Clone, Copy)]
371/// enum Test {
372///     Test1,
373///     Test2,
374/// }
375///
376/// impl From<Test> for u8 {
377///     fn from(val: Test) -> u8 {
378///         match val {
379///             Test::Test1 => 0,
380///             Test::Test2 => 1,
381///         }
382///     }
383/// }
384///
385/// impl TryFrom<u8> for Test {
386///     type Error = ();
387///
388///     fn try_from(val: u8) -> Result<Test, ()> {
389///         match val {
390///             0 => Ok(Test::Test1),
391///             1 => Ok(Test::Test2),
392///             _ => Err(()),
393///         }
394///     }
395/// }
396///
397/// impl PassBy for Test {
398///     type PassBy = Enum<Self>;
399/// }
400/// ```
401pub struct Enum<T: Copy + Into<u8> + TryFrom<u8>>(PhantomData<T>);
402
403#[cfg(feature = "std")]
404impl<T: Copy + Into<u8> + TryFrom<u8>> PassByImpl<T> for Enum<T> {
405	fn into_ffi_value(instance: T, _: &mut dyn FunctionContext) -> Result<Self::FFIType> {
406		Ok(instance.into() as u32)
407	}
408
409	fn from_ffi_value(_: &mut dyn FunctionContext, arg: Self::FFIType) -> Result<T> {
410		T::try_from(arg as u8).map_err(|_| format!("Invalid enum discriminant: {}", arg))
411	}
412}
413
414#[cfg(not(feature = "std"))]
415impl<T: Copy + Into<u8> + TryFrom<u8, Error = ()>> PassByImpl<T> for Enum<T> {
416	type Owned = ();
417
418	fn into_ffi_value(instance: &T) -> WrappedFFIValue<Self::FFIType, Self::Owned> {
419		let value: u8 = (*instance).into();
420		(value as u32).into()
421	}
422
423	fn from_ffi_value(arg: Self::FFIType) -> T {
424		T::try_from(arg as u8).expect("Host to wasm provides a valid enum discriminant; qed")
425	}
426}
427
428/// The type is passed as `u32`.
429///
430/// The value is corresponds to the discriminant of the variant.
431impl<T: Copy + Into<u8> + TryFrom<u8>> RIType for Enum<T> {
432	type FFIType = u32;
433}