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