mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-26 08:47:57 +00:00
Reorganising the repository - external renames and moves (#4074)
* Adding first rough ouline of the repository structure * Remove old CI stuff * add title * formatting fixes * move node-exits job's script to scripts dir * Move docs into subdir * move to bin * move maintainence scripts, configs and helpers into its own dir * add .local to ignore * move core->client * start up 'test' area * move test client * move test runtime * make test move compile * Add dependencies rule enforcement. * Fix indexing. * Update docs to reflect latest changes * Moving /srml->/paint * update docs * move client/sr-* -> primitives/ * clean old readme * remove old broken code in rhd * update lock * Step 1. * starting to untangle client * Fix after merge. * start splitting out client interfaces * move children and blockchain interfaces * Move trie and state-machine to primitives. * Fix WASM builds. * fixing broken imports * more interface moves * move backend and light to interfaces * move CallExecutor * move cli off client * moving around more interfaces * re-add consensus crates into the mix * fix subkey path * relieve client from executor * starting to pull out client from grandpa * move is_decendent_of out of client * grandpa still depends on client directly * lemme tests pass * rename srml->paint * Make it compile. * rename interfaces->client-api * Move keyring to primitives. * fixup libp2p dep * fix broken use * allow dependency enforcement to fail * move fork-tree * Moving wasm-builder * make env * move build-script-utils * fixup broken crate depdencies and names * fix imports for authority discovery * fix typo * update cargo.lock * fixing imports * Fix paths and add missing crates * re-add missing crates
This commit is contained in:
committed by
Bastian Köcher
parent
becc3b0a4f
commit
60e5011c72
@@ -0,0 +1,62 @@
|
||||
// Copyright 2019 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Substrate is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Substrate is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Traits required by the runtime interface from the host side.
|
||||
|
||||
use crate::RIType;
|
||||
|
||||
use wasm_interface::{FunctionContext, Result};
|
||||
|
||||
/// Something that can be converted into a ffi value.
|
||||
pub trait IntoFFIValue: RIType {
|
||||
/// Convert `self` into a ffi value.
|
||||
fn into_ffi_value(self, context: &mut dyn FunctionContext) -> Result<Self::FFIType>;
|
||||
}
|
||||
|
||||
/// Something that can be converted into a preallocated ffi value.
|
||||
///
|
||||
/// Every type parameter that should be given as `&mut` into a runtime interface function, needs
|
||||
/// to implement this trait. After executing the host implementation of the runtime interface
|
||||
/// function, the value is copied into the preallocated wasm memory.
|
||||
///
|
||||
/// This should only be used for types which have a fixed size, like slices. Other types like a vec
|
||||
/// do not work with this interface, as we can not call into wasm to reallocate memory. So, this
|
||||
/// trait should be implemented carefully.
|
||||
pub trait IntoPreallocatedFFIValue: RIType {
|
||||
/// As `Self` can be an unsized type, it needs to be represented by a sized type at the host.
|
||||
/// This `SelfInstance` is the sized type.
|
||||
type SelfInstance;
|
||||
|
||||
/// Convert `self_instance` into the given preallocated ffi value.
|
||||
fn into_preallocated_ffi_value(
|
||||
self_instance: Self::SelfInstance,
|
||||
context: &mut dyn FunctionContext,
|
||||
allocated: Self::FFIType,
|
||||
) -> Result<()>;
|
||||
}
|
||||
|
||||
/// Something that can be created from a ffi value.
|
||||
pub trait FromFFIValue: RIType {
|
||||
/// As `Self` can be an unsized type, it needs to be represented by a sized type at the host.
|
||||
/// This `SelfInstance` is the sized type.
|
||||
type SelfInstance;
|
||||
|
||||
/// Create `SelfInstance` from the given
|
||||
fn from_ffi_value(
|
||||
context: &mut dyn FunctionContext,
|
||||
arg: Self::FFIType,
|
||||
) -> Result<Self::SelfInstance>;
|
||||
}
|
||||
@@ -0,0 +1,491 @@
|
||||
// Copyright 2019 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Substrate is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Substrate is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Provides implementations for the runtime interface traits.
|
||||
|
||||
use crate::{RIType, Pointer, pass_by::{PassBy, Codec, Inner, PassByInner}};
|
||||
#[cfg(feature = "std")]
|
||||
use crate::host::*;
|
||||
#[cfg(not(feature = "std"))]
|
||||
use crate::wasm::*;
|
||||
|
||||
#[cfg(all(not(feature = "std"), not(feature = "disable_target_static_assertions")))]
|
||||
use static_assertions::assert_eq_size;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use wasm_interface::{FunctionContext, Result};
|
||||
|
||||
use codec::{Encode, Decode};
|
||||
|
||||
use rstd::{any::TypeId, mem, vec::Vec};
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use rstd::borrow::Cow;
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
use rstd::{slice, boxed::Box};
|
||||
|
||||
// Make sure that our assumptions for storing a pointer + its size in `u64` is valid.
|
||||
#[cfg(all(not(feature = "std"), not(feature = "disable_target_static_assertions")))]
|
||||
assert_eq_size!(usize, u32);
|
||||
#[cfg(all(not(feature = "std"), not(feature = "disable_target_static_assertions")))]
|
||||
assert_eq_size!(*const u8, u32);
|
||||
|
||||
/// Converts a pointer and length into an `u64`.
|
||||
pub fn pointer_and_len_to_u64(ptr: u32, len: u32) -> u64 {
|
||||
// The static assertions from above are changed into a runtime check.
|
||||
#[cfg(all(feature = "std", not(feature = "disable_target_static_assertions")))]
|
||||
assert_eq!(4, rstd::mem::size_of::<usize>());
|
||||
|
||||
(u64::from(len) << 32) | u64::from(ptr)
|
||||
}
|
||||
|
||||
/// Splits an `u64` into the pointer and length.
|
||||
pub fn pointer_and_len_from_u64(val: u64) -> (u32, u32) {
|
||||
// The static assertions from above are changed into a runtime check.
|
||||
#[cfg(all(feature = "std", not(feature = "disable_target_static_assertions")))]
|
||||
assert_eq!(4, rstd::mem::size_of::<usize>());
|
||||
|
||||
let ptr = (val & (!0u32 as u64)) as u32;
|
||||
let len = (val >> 32) as u32;
|
||||
|
||||
(ptr, len)
|
||||
}
|
||||
|
||||
/// Implement the traits for the given primitive traits.
|
||||
macro_rules! impl_traits_for_primitives {
|
||||
(
|
||||
$(
|
||||
$rty:ty, $fty:ty,
|
||||
)*
|
||||
) => {
|
||||
$(
|
||||
/// The type is passed directly.
|
||||
impl RIType for $rty {
|
||||
type FFIType = $fty;
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
impl IntoFFIValue for $rty {
|
||||
type Owned = ();
|
||||
|
||||
fn into_ffi_value(&self) -> WrappedFFIValue<$fty> {
|
||||
(*self as $fty).into()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
impl FromFFIValue for $rty {
|
||||
fn from_ffi_value(arg: $fty) -> $rty {
|
||||
arg as $rty
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl FromFFIValue for $rty {
|
||||
type SelfInstance = $rty;
|
||||
|
||||
fn from_ffi_value(_: &mut dyn FunctionContext, arg: $fty) -> Result<$rty> {
|
||||
Ok(arg as $rty)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl IntoFFIValue for $rty {
|
||||
fn into_ffi_value(self, _: &mut dyn FunctionContext) -> Result<$fty> {
|
||||
Ok(self as $fty)
|
||||
}
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
impl_traits_for_primitives! {
|
||||
u8, u8,
|
||||
u16, u16,
|
||||
u32, u32,
|
||||
u64, u64,
|
||||
i8, i8,
|
||||
i16, i16,
|
||||
i32, i32,
|
||||
i64, i64,
|
||||
}
|
||||
|
||||
/// `bool` is passed as `u8`.
|
||||
///
|
||||
/// - `1`: true
|
||||
/// - `0`: false
|
||||
impl RIType for bool {
|
||||
type FFIType = u8;
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
impl IntoFFIValue for bool {
|
||||
type Owned = ();
|
||||
|
||||
fn into_ffi_value(&self) -> WrappedFFIValue<u8> {
|
||||
if *self { 1 } else { 0 }.into()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
impl FromFFIValue for bool {
|
||||
fn from_ffi_value(arg: u8) -> bool {
|
||||
arg == 1
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl FromFFIValue for bool {
|
||||
type SelfInstance = bool;
|
||||
|
||||
fn from_ffi_value(_: &mut dyn FunctionContext, arg: u8) -> Result<bool> {
|
||||
Ok(arg == 1)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl IntoFFIValue for bool {
|
||||
fn into_ffi_value(self, _: &mut dyn FunctionContext) -> Result<u8> {
|
||||
Ok(if self { 1 } else { 0 })
|
||||
}
|
||||
}
|
||||
|
||||
/// The type is passed as `u64`.
|
||||
///
|
||||
/// The `u64` value is build by `length 32bit << 32 | pointer 32bit`
|
||||
///
|
||||
/// If `T == u8` the length and the pointer are taken directly from the `Self`.
|
||||
/// Otherwise `Self` is encoded and the length and the pointer are taken from the encoded vector.
|
||||
impl<T> RIType for Vec<T> {
|
||||
type FFIType = u64;
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<T: 'static + Encode> IntoFFIValue for Vec<T> {
|
||||
fn into_ffi_value(self, context: &mut dyn FunctionContext) -> Result<u64> {
|
||||
let vec: Cow<'_, [u8]> = if TypeId::of::<T>() == TypeId::of::<u8>() {
|
||||
unsafe { Cow::Borrowed(mem::transmute(&self[..])) }
|
||||
} else {
|
||||
Cow::Owned(self.encode())
|
||||
};
|
||||
|
||||
let ptr = context.allocate_memory(vec.as_ref().len() as u32)?;
|
||||
context.write_memory(ptr, &vec)?;
|
||||
|
||||
Ok(pointer_and_len_to_u64(ptr.into(), vec.len() as u32))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<T: 'static + Decode> FromFFIValue for Vec<T> {
|
||||
type SelfInstance = Vec<T>;
|
||||
|
||||
fn from_ffi_value(context: &mut dyn FunctionContext, arg: u64) -> Result<Vec<T>> {
|
||||
<[T] as FromFFIValue>::from_ffi_value(context, arg)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
impl<T: 'static + Encode> IntoFFIValue for Vec<T> {
|
||||
type Owned = Vec<u8>;
|
||||
|
||||
fn into_ffi_value(&self) -> WrappedFFIValue<u64, Vec<u8>> {
|
||||
self[..].into_ffi_value()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
impl<T: 'static + Decode> FromFFIValue for Vec<T> {
|
||||
fn from_ffi_value(arg: u64) -> Vec<T> {
|
||||
let (ptr, len) = pointer_and_len_from_u64(arg);
|
||||
let len = len as usize;
|
||||
|
||||
if TypeId::of::<T>() == TypeId::of::<u8>() {
|
||||
unsafe { mem::transmute(Vec::from_raw_parts(ptr as *mut u8, len, len)) }
|
||||
} else {
|
||||
let slice = unsafe { slice::from_raw_parts(ptr as *const u8, len) };
|
||||
Self::decode(&mut &slice[..]).expect("Host to wasm values are encoded correctly; qed")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The type is passed as `u64`.
|
||||
///
|
||||
/// The `u64` value is build by `length 32bit << 32 | pointer 32bit`
|
||||
///
|
||||
/// If `T == u8` the length and the pointer are taken directly from the `Self`.
|
||||
/// Otherwise `Self` is encoded and the length and the pointer are taken from the encoded vector.
|
||||
impl<T> RIType for [T] {
|
||||
type FFIType = u64;
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<T: 'static + Decode> FromFFIValue for [T] {
|
||||
type SelfInstance = Vec<T>;
|
||||
|
||||
fn from_ffi_value(context: &mut dyn FunctionContext, arg: u64) -> Result<Vec<T>> {
|
||||
let (ptr, len) = pointer_and_len_from_u64(arg);
|
||||
|
||||
let vec = context.read_memory(Pointer::new(ptr), len)?;
|
||||
|
||||
if TypeId::of::<T>() == TypeId::of::<u8>() {
|
||||
Ok(unsafe { mem::transmute(vec) })
|
||||
} else {
|
||||
Ok(Vec::<T>::decode(&mut &vec[..]).expect("Wasm to host values are encoded correctly; qed"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl IntoPreallocatedFFIValue for [u8] {
|
||||
type SelfInstance = Vec<u8>;
|
||||
|
||||
fn into_preallocated_ffi_value(
|
||||
self_instance: Self::SelfInstance,
|
||||
context: &mut dyn FunctionContext,
|
||||
allocated: u64,
|
||||
) -> Result<()> {
|
||||
let (ptr, len) = pointer_and_len_from_u64(allocated);
|
||||
|
||||
if (len as usize) < self_instance.len() {
|
||||
Err(
|
||||
format!(
|
||||
"Preallocated buffer is not big enough (given {} vs needed {})!",
|
||||
len,
|
||||
self_instance.len()
|
||||
)
|
||||
)
|
||||
} else {
|
||||
context.write_memory(Pointer::new(ptr), &self_instance)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
impl<T: 'static + Encode> IntoFFIValue for [T] {
|
||||
type Owned = Vec<u8>;
|
||||
|
||||
fn into_ffi_value(&self) -> WrappedFFIValue<u64, Vec<u8>> {
|
||||
if TypeId::of::<T>() == TypeId::of::<u8>() {
|
||||
let slice = unsafe { mem::transmute::<&[T], &[u8]>(self) };
|
||||
pointer_and_len_to_u64(slice.as_ptr() as u32, slice.len() as u32).into()
|
||||
} else {
|
||||
let data = self.encode();
|
||||
let ffi_value = pointer_and_len_to_u64(data.as_ptr() as u32, data.len() as u32);
|
||||
(ffi_value, data).into()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Implement the traits for the `[u8; N]` arrays, where `N` is the input to this macro.
|
||||
macro_rules! impl_traits_for_arrays {
|
||||
(
|
||||
$(
|
||||
$n:expr
|
||||
),*
|
||||
$(,)?
|
||||
) => {
|
||||
$(
|
||||
/// The type is passed as `u32`.
|
||||
///
|
||||
/// The `u32` is the pointer to the array.
|
||||
impl RIType for [u8; $n] {
|
||||
type FFIType = u32;
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
impl IntoFFIValue for [u8; $n] {
|
||||
type Owned = ();
|
||||
|
||||
fn into_ffi_value(&self) -> WrappedFFIValue<u32> {
|
||||
(self.as_ptr() as u32).into()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
impl FromFFIValue for [u8; $n] {
|
||||
fn from_ffi_value(arg: u32) -> [u8; $n] {
|
||||
let mut res = unsafe { mem::MaybeUninit::<[u8; $n]>::zeroed().assume_init() };
|
||||
res.copy_from_slice(unsafe { slice::from_raw_parts(arg as *const u8, $n) });
|
||||
|
||||
// Make sure we free the pointer.
|
||||
let _ = unsafe { Box::from_raw(arg as *mut u8) };
|
||||
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl FromFFIValue for [u8; $n] {
|
||||
type SelfInstance = [u8; $n];
|
||||
|
||||
fn from_ffi_value(context: &mut dyn FunctionContext, arg: u32) -> Result<[u8; $n]> {
|
||||
let data = context.read_memory(Pointer::new(arg), $n)?;
|
||||
let mut res = unsafe { mem::MaybeUninit::<[u8; $n]>::zeroed().assume_init() };
|
||||
res.copy_from_slice(&data);
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl IntoFFIValue for [u8; $n] {
|
||||
fn into_ffi_value(self, context: &mut dyn FunctionContext) -> Result<u32> {
|
||||
let addr = context.allocate_memory($n)?;
|
||||
context.write_memory(addr, &self)?;
|
||||
Ok(addr.into())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl IntoPreallocatedFFIValue for [u8; $n] {
|
||||
type SelfInstance = [u8; $n];
|
||||
|
||||
fn into_preallocated_ffi_value(
|
||||
self_instance: Self::SelfInstance,
|
||||
context: &mut dyn FunctionContext,
|
||||
allocated: u32,
|
||||
) -> Result<()> {
|
||||
context.write_memory(Pointer::new(allocated), &self_instance)
|
||||
}
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
impl_traits_for_arrays! {
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
|
||||
27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
|
||||
51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
|
||||
75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96,
|
||||
}
|
||||
|
||||
impl<T: codec::Codec, E: codec::Codec> PassBy for rstd::result::Result<T, E> {
|
||||
type PassBy = Codec<Self>;
|
||||
}
|
||||
|
||||
impl<T: codec::Codec> PassBy for Option<T> {
|
||||
type PassBy = Codec<Self>;
|
||||
}
|
||||
|
||||
/// Implement `PassBy` with `Inner` for the given fixed sized hash types.
|
||||
macro_rules! for_primitive_types {
|
||||
{ $( $hash:ident $n:expr ),* $(,)? } => {
|
||||
$(
|
||||
impl PassBy for primitive_types::$hash {
|
||||
type PassBy = Inner<Self, [u8; $n]>;
|
||||
}
|
||||
|
||||
impl PassByInner for primitive_types::$hash {
|
||||
type Inner = [u8; $n];
|
||||
|
||||
fn inner(&self) -> &Self::Inner {
|
||||
&self.0
|
||||
}
|
||||
|
||||
fn into_inner(self) -> Self::Inner {
|
||||
self.0
|
||||
}
|
||||
|
||||
fn from_inner(inner: Self::Inner) -> Self {
|
||||
Self(inner)
|
||||
}
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
for_primitive_types! {
|
||||
H160 20,
|
||||
H256 32,
|
||||
H512 64,
|
||||
}
|
||||
|
||||
/// The type is passed as `u64`.
|
||||
///
|
||||
/// The `u64` value is build by `length 32bit << 32 | pointer 32bit`
|
||||
///
|
||||
/// The length and the pointer are taken directly from the `Self`.
|
||||
impl RIType for str {
|
||||
type FFIType = u64;
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl FromFFIValue for str {
|
||||
type SelfInstance = String;
|
||||
|
||||
fn from_ffi_value(context: &mut dyn FunctionContext, arg: u64) -> Result<String> {
|
||||
let (ptr, len) = pointer_and_len_from_u64(arg);
|
||||
|
||||
let vec = context.read_memory(Pointer::new(ptr), len)?;
|
||||
|
||||
// The data is valid utf8, as it is stored as `&str` in wasm.
|
||||
String::from_utf8(vec).map_err(|_| "Invalid utf8 data provided".into())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
impl IntoFFIValue for str {
|
||||
type Owned = ();
|
||||
|
||||
fn into_ffi_value(&self) -> WrappedFFIValue<u64, ()> {
|
||||
let bytes = self.as_bytes();
|
||||
pointer_and_len_to_u64(bytes.as_ptr() as u32, bytes.len() as u32).into()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<T: wasm_interface::PointerType> RIType for Pointer<T> {
|
||||
type FFIType = u32;
|
||||
}
|
||||
|
||||
/// The type is passed as `u32`.
|
||||
#[cfg(not(feature = "std"))]
|
||||
impl<T> RIType for Pointer<T> {
|
||||
type FFIType = u32;
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
impl<T> IntoFFIValue for Pointer<T> {
|
||||
type Owned = ();
|
||||
|
||||
fn into_ffi_value(&self) -> WrappedFFIValue<u32> {
|
||||
(*self as u32).into()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
impl<T> FromFFIValue for Pointer<T> {
|
||||
fn from_ffi_value(arg: u32) -> Self {
|
||||
arg as _
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<T: wasm_interface::PointerType> FromFFIValue for Pointer<T> {
|
||||
type SelfInstance = Self;
|
||||
|
||||
fn from_ffi_value(_: &mut dyn FunctionContext, arg: u32) -> Result<Self> {
|
||||
Ok(Pointer::new(arg))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<T: wasm_interface::PointerType> IntoFFIValue for Pointer<T> {
|
||||
fn into_ffi_value(self, _: &mut dyn FunctionContext) -> Result<u32> {
|
||||
Ok(self.into())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,212 @@
|
||||
// Copyright 2019 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Substrate is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Substrate is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Substrate runtime interface
|
||||
//!
|
||||
//! This crate provides types, traits and macros around runtime interfaces. A runtime interface is
|
||||
//! a fixed interface between a Substrate runtime and a Substrate node. For a native runtime the
|
||||
//! interface maps to a direct function call of the implementation. For a wasm runtime the interface
|
||||
//! maps to an external function call. These external functions are exported by the wasm executor
|
||||
//! and they map to the same implementation as the native calls.
|
||||
//!
|
||||
//! # Using a type in a runtime interface
|
||||
//!
|
||||
//! Any type that should be used in a runtime interface as argument or return value needs to
|
||||
//! implement [`RIType`]. The associated type `FFIType` is the type that is used in the FFI
|
||||
//! function to represent the actual type. For example `[T]` is represented by an `u64`. The slice
|
||||
//! pointer and the length will be mapped to an `u64` value. For more information, see the
|
||||
//! implementation of [`RIType`] for [`T`]. The FFI function definition is used when calling from
|
||||
//! the wasm runtime into the node.
|
||||
//!
|
||||
//! Traits are used to convert from a type to the corresponding [`RIType::FFIType`].
|
||||
//! Depending on where and how a type should be used in a function signature, a combination of the
|
||||
//! following traits need to be implemented:
|
||||
//!
|
||||
//! 1. Pass as function argument: [`wasm::IntoFFIValue`] and [`host::FromFFIValue`]
|
||||
//! 2. As function return value: [`wasm::FromFFIValue`] and [`host::IntoFFIValue`]
|
||||
//! 3. Pass as mutable function argument: [`host::IntoPreallocatedFFIValue`]
|
||||
//!
|
||||
//! The traits are implemented for most of the common types like `[T]`, `Vec<T>`, arrays and
|
||||
//! primitive types.
|
||||
//!
|
||||
//! For custom types, we provide the [`PassBy`](pass_by::PassBy) trait and strategies that define
|
||||
//! how a type is passed between the wasm runtime and the node. Each strategy also provides a derive
|
||||
//! macro to simplify the implementation.
|
||||
//!
|
||||
//! # Performance
|
||||
//!
|
||||
//! To not waste any more performance when calling into the node, not all types are SCALE encoded
|
||||
//! when being passed as arguments between the wasm runtime and the node. For most types that
|
||||
//! are raw bytes like `Vec<u8>`, `[u8]` or `[u8; N]` we pass them directly, without SCALE encoding
|
||||
//! them in front of. The implementation of [`RIType`] each type provides more information on how
|
||||
//! the data is passed.
|
||||
//!
|
||||
//! # Declaring a runtime interface
|
||||
//!
|
||||
//! Declaring a runtime interface is similar to declaring a trait in Rust:
|
||||
//!
|
||||
//! ```
|
||||
//! #[substrate_runtime_interface::runtime_interface]
|
||||
//! trait RuntimeInterface {
|
||||
//! fn some_function(value: &[u8]) -> bool {
|
||||
//! value.iter().all(|v| *v > 125)
|
||||
//! }
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! For more information on declaring a runtime interface, see
|
||||
//! [`#[runtime_interface]`](attr.runtime_interface.html).
|
||||
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
#[doc(hidden)]
|
||||
#[cfg(feature = "std")]
|
||||
pub use wasm_interface;
|
||||
|
||||
#[doc(hidden)]
|
||||
pub use rstd;
|
||||
|
||||
pub use substrate_runtime_interface_proc_macro::runtime_interface;
|
||||
|
||||
#[doc(hidden)]
|
||||
#[cfg(feature = "std")]
|
||||
pub use externalities::{
|
||||
set_and_run_with_externalities, with_externalities, Externalities, ExternalitiesExt, ExtensionStore,
|
||||
};
|
||||
|
||||
#[doc(hidden)]
|
||||
pub use codec;
|
||||
|
||||
pub(crate) mod impls;
|
||||
#[cfg(feature = "std")]
|
||||
pub mod host;
|
||||
#[cfg(not(feature = "std"))]
|
||||
pub mod wasm;
|
||||
pub mod pass_by;
|
||||
|
||||
/// Something that can be used by the runtime interface as type to communicate between wasm and the
|
||||
/// host.
|
||||
///
|
||||
/// Every type that should be used in a runtime interface function signature needs to implement
|
||||
/// this trait.
|
||||
pub trait RIType {
|
||||
/// The ffi type that is used to represent `Self`.
|
||||
#[cfg(feature = "std")]
|
||||
type FFIType: wasm_interface::IntoValue + wasm_interface::TryFromValue;
|
||||
#[cfg(not(feature = "std"))]
|
||||
type FFIType;
|
||||
}
|
||||
|
||||
/// A pointer that can be used in a runtime interface function signature.
|
||||
#[cfg(not(feature = "std"))]
|
||||
pub type Pointer<T> = *mut T;
|
||||
|
||||
/// A pointer that can be used in a runtime interface function signature.
|
||||
#[cfg(feature = "std")]
|
||||
pub type Pointer<T> = wasm_interface::Pointer<T>;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use test_wasm::{WASM_BINARY, test_api::HostFunctions};
|
||||
use wasm_interface::HostFunctions as HostFunctionsT;
|
||||
|
||||
type TestExternalities = state_machine::TestExternalities<primitives::Blake2Hasher, u64>;
|
||||
|
||||
fn call_wasm_method<HF: HostFunctionsT>(method: &str) -> TestExternalities {
|
||||
let mut ext = TestExternalities::default();
|
||||
let mut ext_ext = ext.ext();
|
||||
|
||||
executor::call_in_wasm::<
|
||||
_,
|
||||
(
|
||||
HF,
|
||||
runtime_io::SubstrateHostFunctions,
|
||||
executor::deprecated_host_interface::SubstrateExternals
|
||||
)
|
||||
>(
|
||||
method,
|
||||
&[],
|
||||
executor::WasmExecutionMethod::Interpreted,
|
||||
&mut ext_ext,
|
||||
&WASM_BINARY[..],
|
||||
8,
|
||||
).expect(&format!("Executes `{}`", method));
|
||||
|
||||
ext
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_return_data() {
|
||||
call_wasm_method::<HostFunctions>("test_return_data");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_return_option_data() {
|
||||
call_wasm_method::<HostFunctions>("test_return_option_data");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_set_storage() {
|
||||
let mut ext = call_wasm_method::<HostFunctions>("test_set_storage");
|
||||
|
||||
let expected = "world";
|
||||
assert_eq!(expected.as_bytes(), &ext.ext().storage("hello".as_bytes()).unwrap()[..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_return_value_into_mutable_reference() {
|
||||
call_wasm_method::<HostFunctions>("test_return_value_into_mutable_reference");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_and_return_array() {
|
||||
call_wasm_method::<HostFunctions>("test_get_and_return_array");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_array_as_mutable_reference() {
|
||||
call_wasm_method::<HostFunctions>("test_array_as_mutable_reference");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_return_input_public_key() {
|
||||
call_wasm_method::<HostFunctions>("test_return_input_public_key");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(
|
||||
expected = "Other(\"Instantiation: Export ext_test_api_return_input_version_1 not found\")"
|
||||
)]
|
||||
fn host_function_not_found() {
|
||||
call_wasm_method::<()>("test_return_data");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(
|
||||
expected =
|
||||
"FunctionExecution(\"ext_test_api_invalid_utf8_data_version_1\", \
|
||||
\"Invalid utf8 data provided\")"
|
||||
)]
|
||||
fn test_invalid_utf8_data_should_return_an_error() {
|
||||
call_wasm_method::<HostFunctions>("test_invalid_utf8_data_should_return_an_error");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_overwrite_native_function_implementation() {
|
||||
call_wasm_method::<HostFunctions>("test_overwrite_native_function_implementation");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,384 @@
|
||||
// Copyright 2019 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Substrate is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Substrate is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Provides the [`PassBy`](pass_by::PassBy) trait to simplify the implementation of the
|
||||
//! runtime interface traits for custom types.
|
||||
//!
|
||||
//! [`Codec`](pass_by::Codec), [`Inner`](pass_by::Inner) and [`Enum`](pass_by::Enum) are the
|
||||
//! provided strategy implementations.
|
||||
|
||||
use crate::{RIType, impls::{pointer_and_len_from_u64, pointer_and_len_to_u64}};
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use crate::host::*;
|
||||
#[cfg(not(feature = "std"))]
|
||||
use crate::wasm::*;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use wasm_interface::{FunctionContext, Pointer, Result};
|
||||
|
||||
use rstd::{marker::PhantomData, convert::TryFrom};
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
use rstd::{slice, vec::Vec};
|
||||
|
||||
pub use substrate_runtime_interface_proc_macro::{PassByCodec, PassByInner, PassByEnum};
|
||||
|
||||
/// Something that should be passed between wasm and the host using the given strategy.
|
||||
///
|
||||
/// See [`Codec`], [`Inner`] or [`Enum`] for more information about the provided strategies.
|
||||
pub trait PassBy: Sized {
|
||||
/// The strategy that should be used to pass the type.
|
||||
type PassBy: PassByImpl<Self>;
|
||||
}
|
||||
|
||||
/// Something that provides a strategy for passing a type between wasm and the host.
|
||||
///
|
||||
/// This trait exposes the same functionality as [`crate::host::IntoFFIValue`] and
|
||||
/// [`crate::host::FromFFIValue`] to delegate the implementation for a type to a different type.
|
||||
///
|
||||
/// This trait is used for the host implementation.
|
||||
#[cfg(feature = "std")]
|
||||
pub trait PassByImpl<T>: RIType {
|
||||
/// Convert the given instance to the ffi value.
|
||||
///
|
||||
/// For more information see: [`crate::host::IntoFFIValue::into_ffi_value`]
|
||||
fn into_ffi_value(
|
||||
instance: T,
|
||||
context: &mut dyn FunctionContext,
|
||||
) -> Result<Self::FFIType>;
|
||||
|
||||
/// Create `T` from the given ffi value.
|
||||
///
|
||||
/// For more information see: [`crate::host::FromFFIValue::from_ffi_value`]
|
||||
fn from_ffi_value(
|
||||
context: &mut dyn FunctionContext,
|
||||
arg: Self::FFIType,
|
||||
) -> Result<T>;
|
||||
}
|
||||
|
||||
/// Something that provides a strategy for passing a type between wasm and the host.
|
||||
///
|
||||
/// This trait exposes the same functionality as [`crate::wasm::IntoFFIValue`] and
|
||||
/// [`crate::wasm::FromFFIValue`] to delegate the implementation for a type to a different type.
|
||||
///
|
||||
/// This trait is used for the wasm implementation.
|
||||
#[cfg(not(feature = "std"))]
|
||||
pub trait PassByImpl<T>: RIType {
|
||||
/// The owned rust type that is stored with the ffi value in [`crate::wasm::WrappedFFIValue`].
|
||||
type Owned;
|
||||
|
||||
/// Convert the given `instance` into [`crate::wasm::WrappedFFIValue`].
|
||||
///
|
||||
/// For more information see: [`crate::wasm::IntoFFIValue::into_ffi_value`]
|
||||
fn into_ffi_value(instance: &T) -> WrappedFFIValue<Self::FFIType, Self::Owned>;
|
||||
|
||||
/// Create `T` from the given ffi value.
|
||||
///
|
||||
/// For more information see: [`crate::wasm::FromFFIValue::from_ffi_value`]
|
||||
fn from_ffi_value(arg: Self::FFIType) -> T;
|
||||
}
|
||||
|
||||
impl<T: PassBy> RIType for T {
|
||||
type FFIType = <T::PassBy as RIType>::FFIType;
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<T: PassBy> IntoFFIValue for T {
|
||||
fn into_ffi_value(
|
||||
self,
|
||||
context: &mut dyn FunctionContext,
|
||||
) -> Result<<T::PassBy as RIType>::FFIType> {
|
||||
T::PassBy::into_ffi_value(self, context)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<T: PassBy> FromFFIValue for T {
|
||||
type SelfInstance = Self;
|
||||
|
||||
fn from_ffi_value(
|
||||
context: &mut dyn FunctionContext,
|
||||
arg: <T::PassBy as RIType>::FFIType,
|
||||
) -> Result<Self> {
|
||||
T::PassBy::from_ffi_value(context, arg)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
impl<T: PassBy> IntoFFIValue for T {
|
||||
type Owned = <T::PassBy as PassByImpl<T>>::Owned;
|
||||
|
||||
fn into_ffi_value(&self) -> WrappedFFIValue<<T::PassBy as RIType>::FFIType, Self::Owned> {
|
||||
T::PassBy::into_ffi_value(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
impl<T: PassBy> FromFFIValue for T {
|
||||
fn from_ffi_value(arg: <T::PassBy as RIType>::FFIType) -> Self {
|
||||
T::PassBy::from_ffi_value(arg)
|
||||
}
|
||||
}
|
||||
|
||||
/// The implementation of the pass by codec strategy. This strategy uses a SCALE encoded
|
||||
/// representation of the type between wasm and the host.
|
||||
///
|
||||
/// Use this type as associated type for [`PassBy`] to implement this strategy for a type.
|
||||
///
|
||||
/// This type expects the type that wants to implement this strategy as generic parameter.
|
||||
///
|
||||
/// [`PassByCodec`](derive.PassByCodec.html) is a derive macro to implement this strategy.
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// # use substrate_runtime_interface::pass_by::{PassBy, Codec};
|
||||
/// #[derive(codec::Encode, codec::Decode)]
|
||||
/// struct Test;
|
||||
///
|
||||
/// impl PassBy for Test {
|
||||
/// type PassBy = Codec<Self>;
|
||||
/// }
|
||||
/// ```
|
||||
pub struct Codec<T: codec::Codec>(PhantomData<T>);
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<T: codec::Codec> PassByImpl<T> for Codec<T> {
|
||||
fn into_ffi_value(
|
||||
instance: T,
|
||||
context: &mut dyn FunctionContext,
|
||||
) -> Result<Self::FFIType> {
|
||||
let vec = instance.encode();
|
||||
let ptr = context.allocate_memory(vec.len() as u32)?;
|
||||
context.write_memory(ptr, &vec)?;
|
||||
|
||||
Ok(pointer_and_len_to_u64(ptr.into(), vec.len() as u32))
|
||||
}
|
||||
|
||||
fn from_ffi_value(
|
||||
context: &mut dyn FunctionContext,
|
||||
arg: Self::FFIType,
|
||||
) -> Result<T> {
|
||||
let (ptr, len) = pointer_and_len_from_u64(arg);
|
||||
let vec = context.read_memory(Pointer::new(ptr), len)?;
|
||||
T::decode(&mut &vec[..])
|
||||
.map_err(|e| format!("Could not decode value from wasm: {}", e.what()))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
impl<T: codec::Codec> PassByImpl<T> for Codec<T> {
|
||||
type Owned = Vec<u8>;
|
||||
|
||||
fn into_ffi_value(instance: &T) -> WrappedFFIValue<Self::FFIType, Self::Owned> {
|
||||
let data = instance.encode();
|
||||
let ffi_value = pointer_and_len_to_u64(data.as_ptr() as u32, data.len() as u32);
|
||||
(ffi_value, data).into()
|
||||
}
|
||||
|
||||
fn from_ffi_value(arg: Self::FFIType) -> T {
|
||||
let (ptr, len) = pointer_and_len_from_u64(arg);
|
||||
let len = len as usize;
|
||||
|
||||
let slice = unsafe { slice::from_raw_parts(ptr as *const u8, len) };
|
||||
T::decode(&mut &slice[..]).expect("Host to wasm values are encoded correctly; qed")
|
||||
}
|
||||
}
|
||||
|
||||
/// The type is passed as `u64`.
|
||||
///
|
||||
/// The `u64` value is build by `length 32bit << 32 | pointer 32bit`
|
||||
///
|
||||
/// `Self` is encoded and the length and the pointer are taken from the encoded vector.
|
||||
impl<T: codec::Codec> RIType for Codec<T> {
|
||||
type FFIType = u64;
|
||||
}
|
||||
|
||||
/// Trait that needs to be implemented by a type that should be passed between wasm and the host,
|
||||
/// by using the inner type. See [`Inner`] for more information.
|
||||
pub trait PassByInner: Sized {
|
||||
/// The inner type that is wrapped by `Self`.
|
||||
type Inner: RIType;
|
||||
|
||||
/// Consumes `self` and returns the inner type.
|
||||
fn into_inner(self) -> Self::Inner;
|
||||
|
||||
/// Returns the reference to the inner type.
|
||||
fn inner(&self) -> &Self::Inner;
|
||||
|
||||
/// Construct `Self` from the given `inner`.
|
||||
fn from_inner(inner: Self::Inner) -> Self;
|
||||
}
|
||||
|
||||
/// The implementation of the pass by inner type strategy. The type that uses this strategy will be
|
||||
/// passed between wasm and the host by using the wrapped inner type. So, this strategy is only
|
||||
/// usable by newtype structs.
|
||||
///
|
||||
/// Use this type as associated type for [`PassBy`] to implement this strategy for a type. Besides
|
||||
/// that the `PassByInner` trait need to be implemented as well.
|
||||
///
|
||||
/// This type expects the type that wants to use this strategy as generic parameter `T` and the
|
||||
/// inner type as generic parameter `I`.
|
||||
///
|
||||
/// [`PassByInner`](derive.PassByInner.html) is a derive macro to implement this strategy.
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// # use substrate_runtime_interface::pass_by::{PassBy, Inner, PassByInner};
|
||||
/// struct Test([u8; 32]);
|
||||
///
|
||||
/// impl PassBy for Test {
|
||||
/// type PassBy = Inner<Self, [u8; 32]>;
|
||||
/// }
|
||||
///
|
||||
/// impl PassByInner for Test {
|
||||
/// type Inner = [u8; 32];
|
||||
///
|
||||
/// fn into_inner(self) -> [u8; 32] {
|
||||
/// self.0
|
||||
/// }
|
||||
/// fn inner(&self) -> &[u8; 32] {
|
||||
/// &self.0
|
||||
/// }
|
||||
/// fn from_inner(inner: [u8; 32]) -> Self {
|
||||
/// Self(inner)
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
pub struct Inner<T: PassByInner<Inner = I>, I: RIType>(PhantomData<(T, I)>);
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<T: PassByInner<Inner = I>, I: RIType> PassByImpl<T> for Inner<T, I>
|
||||
where I: IntoFFIValue + FromFFIValue<SelfInstance=I>
|
||||
{
|
||||
fn into_ffi_value(
|
||||
instance: T,
|
||||
context: &mut dyn FunctionContext,
|
||||
) -> Result<Self::FFIType> {
|
||||
instance.into_inner().into_ffi_value(context)
|
||||
}
|
||||
|
||||
fn from_ffi_value(
|
||||
context: &mut dyn FunctionContext,
|
||||
arg: Self::FFIType,
|
||||
) -> Result<T> {
|
||||
I::from_ffi_value(context, arg).map(T::from_inner)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
impl<T: PassByInner<Inner = I>, I: RIType> PassByImpl<T> for Inner<T, I>
|
||||
where I: IntoFFIValue + FromFFIValue
|
||||
{
|
||||
type Owned = I::Owned;
|
||||
|
||||
fn into_ffi_value(instance: &T) -> WrappedFFIValue<Self::FFIType, Self::Owned> {
|
||||
instance.inner().into_ffi_value()
|
||||
}
|
||||
|
||||
fn from_ffi_value(arg: Self::FFIType) -> T {
|
||||
T::from_inner(I::from_ffi_value(arg))
|
||||
}
|
||||
}
|
||||
|
||||
/// The type is passed as the inner type.
|
||||
impl<T: PassByInner<Inner = I>, I: RIType> RIType for Inner<T, I> {
|
||||
type FFIType = I::FFIType;
|
||||
}
|
||||
|
||||
/// The implementation of the pass by enum strategy. This strategy uses an `u8` internally to pass
|
||||
/// the enum between wasm and the host. So, this strategy only supports enums with unit variants.
|
||||
///
|
||||
/// Use this type as associated type for [`PassBy`] to implement this strategy for a type.
|
||||
///
|
||||
/// This type expects the type that wants to implement this strategy as generic parameter. Besides
|
||||
/// that the type needs to implement `TryFrom<u8>` and `From<Self> for u8`.
|
||||
///
|
||||
/// [`PassByEnum`](derive.PassByEnum.html) is a derive macro to implement this strategy.
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// # use substrate_runtime_interface::pass_by::{PassBy, Enum};
|
||||
/// #[derive(Clone, Copy)]
|
||||
/// enum Test {
|
||||
/// Test1,
|
||||
/// Test2,
|
||||
/// }
|
||||
///
|
||||
/// impl From<Test> for u8 {
|
||||
/// fn from(val: Test) -> u8 {
|
||||
/// match val {
|
||||
/// Test::Test1 => 0,
|
||||
/// Test::Test2 => 1,
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// impl std::convert::TryFrom<u8> for Test {
|
||||
/// type Error = ();
|
||||
///
|
||||
/// fn try_from(val: u8) -> Result<Test, ()> {
|
||||
/// match val {
|
||||
/// 0 => Ok(Test::Test1),
|
||||
/// 1 => Ok(Test::Test2),
|
||||
/// _ => Err(()),
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// impl PassBy for Test {
|
||||
/// type PassBy = Enum<Self>;
|
||||
/// }
|
||||
/// ```
|
||||
pub struct Enum<T: Copy + Into<u8> + TryFrom<u8>>(PhantomData<T>);
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<T: Copy + Into<u8> + TryFrom<u8>> PassByImpl<T> for Enum<T> {
|
||||
fn into_ffi_value(
|
||||
instance: T,
|
||||
_: &mut dyn FunctionContext,
|
||||
) -> Result<Self::FFIType> {
|
||||
Ok(instance.into())
|
||||
}
|
||||
|
||||
fn from_ffi_value(
|
||||
_: &mut dyn FunctionContext,
|
||||
arg: Self::FFIType,
|
||||
) -> Result<T> {
|
||||
T::try_from(arg).map_err(|_| format!("Invalid enum discriminant: {}", arg))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
impl<T: Copy + Into<u8> + TryFrom<u8, Error = ()>> PassByImpl<T> for Enum<T> {
|
||||
type Owned = ();
|
||||
|
||||
fn into_ffi_value(instance: &T) -> WrappedFFIValue<Self::FFIType, Self::Owned> {
|
||||
let value: u8 = (*instance).into();
|
||||
value.into()
|
||||
}
|
||||
|
||||
fn from_ffi_value(arg: Self::FFIType) -> T {
|
||||
T::try_from(arg).expect("Host to wasm provides a valid enum discriminant; qed")
|
||||
}
|
||||
}
|
||||
|
||||
/// The type is passed as `u8`.
|
||||
///
|
||||
/// The value is corresponds to the discriminant of the variant.
|
||||
impl<T: Copy + Into<u8> + TryFrom<u8>> RIType for Enum<T> {
|
||||
type FFIType = u8;
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
// Copyright 2019 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Substrate is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Substrate is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Traits required by the runtime interface from the wasm side.
|
||||
|
||||
use crate::RIType;
|
||||
|
||||
use rstd::cell::Cell;
|
||||
|
||||
/// Something that can be created from a ffi value.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// It is unsafe behavior to call `Something::into_ffi_value().get()` and take this as input for
|
||||
/// `from_ffi_value`. Implementations are safe to assume that the `arg` given to `from_ffi_value`
|
||||
/// is only generated by the corresponding `host::IntoFFIValue` implementation.
|
||||
pub trait FromFFIValue: Sized + RIType {
|
||||
/// Create `Self` from the given ffi value.
|
||||
fn from_ffi_value(arg: Self::FFIType) -> Self;
|
||||
}
|
||||
|
||||
/// Something that can be converted into a ffi value.
|
||||
pub trait IntoFFIValue: RIType {
|
||||
/// The owned rust type that is stored with the ffi value in [`WrappedFFIValue`].
|
||||
///
|
||||
/// If no owned value is required, `()` can be used as a type.
|
||||
type Owned;
|
||||
|
||||
/// Convert `self` into a [`WrappedFFIValue`].
|
||||
fn into_ffi_value(&self) -> WrappedFFIValue<Self::FFIType, Self::Owned>;
|
||||
}
|
||||
|
||||
/// Represents a wrapped ffi value.
|
||||
///
|
||||
/// It is either the ffi value itself or the ffi value plus some other owned value. By providing
|
||||
/// support for storing another owned value besides the actual ffi value certain performance
|
||||
/// optimizations can be applied. For example using the pointer to a `Vec<u8>`, while using the
|
||||
/// pointer to a SCALE encoded `Vec<u8>` that is stored in this wrapper for any other `Vec<T>`.
|
||||
pub enum WrappedFFIValue<T, O = ()> {
|
||||
Wrapped(T),
|
||||
WrappedAndOwned(T, O),
|
||||
}
|
||||
|
||||
impl<T: Copy, O> WrappedFFIValue<T, O> {
|
||||
/// Returns the wrapped ffi value.
|
||||
pub fn get(&self) -> T {
|
||||
match self {
|
||||
Self::Wrapped(data) | Self::WrappedAndOwned(data, _) => *data,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, O> From<T> for WrappedFFIValue<T, O> {
|
||||
fn from(val: T) -> Self {
|
||||
WrappedFFIValue::Wrapped(val)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, O> From<(T, O)> for WrappedFFIValue<T, O> {
|
||||
fn from(val: (T, O)) -> Self {
|
||||
WrappedFFIValue::WrappedAndOwned(val.0, val.1)
|
||||
}
|
||||
}
|
||||
|
||||
/// The state of an exchangeable function.
|
||||
#[derive(Clone, Copy)]
|
||||
enum ExchangeableFunctionState {
|
||||
/// Original function is present
|
||||
Original,
|
||||
/// The function has been replaced.
|
||||
Replaced,
|
||||
}
|
||||
|
||||
/// A function which implementation can be exchanged.
|
||||
///
|
||||
/// Internally this works by swapping function pointers.
|
||||
pub struct ExchangeableFunction<T>(Cell<(T, ExchangeableFunctionState)>);
|
||||
|
||||
impl<T> ExchangeableFunction<T> {
|
||||
/// Create a new instance of `ExchangeableFunction`.
|
||||
pub const fn new(impl_: T) -> Self {
|
||||
Self(Cell::new((impl_, ExchangeableFunctionState::Original)))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy> ExchangeableFunction<T> {
|
||||
/// Replace the implementation with `new_impl`.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics when trying to replace an already replaced implementation.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// Returns the original implementation wrapped in [`RestoreImplementation`].
|
||||
pub fn replace_implementation(&'static self, new_impl: T) -> RestoreImplementation<T> {
|
||||
if let ExchangeableFunctionState::Replaced = self.0.get().1 {
|
||||
panic!("Trying to replace an already replaced implementation!")
|
||||
}
|
||||
|
||||
let old = self.0.replace((new_impl, ExchangeableFunctionState::Replaced));
|
||||
|
||||
RestoreImplementation(self, Some(old.0))
|
||||
}
|
||||
|
||||
/// Restore the original implementation.
|
||||
fn restore_orig_implementation(&self, orig: T) {
|
||||
self.0.set((orig, ExchangeableFunctionState::Original));
|
||||
}
|
||||
|
||||
/// Returns the internal function pointer.
|
||||
pub fn get(&self) -> T {
|
||||
self.0.get().0
|
||||
}
|
||||
}
|
||||
|
||||
// Wasm does not support threads, so this is safe; qed.
|
||||
unsafe impl<T> Sync for ExchangeableFunction<T> {}
|
||||
|
||||
/// Restores a function implementation on drop.
|
||||
///
|
||||
/// Stores a static reference to the function object and the original implementation.
|
||||
pub struct RestoreImplementation<T: 'static + Copy>(&'static ExchangeableFunction<T>, Option<T>);
|
||||
|
||||
impl<T: Copy> Drop for RestoreImplementation<T> {
|
||||
fn drop(&mut self) {
|
||||
self.0.restore_orig_implementation(self.1.take().expect("Value is only taken on drop; qed"));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user