feat: Rebrand Polkadot/Substrate references to PezkuwiChain
This commit systematically rebrands various references from Parity Technologies' Polkadot/Substrate ecosystem to PezkuwiChain within the kurdistan-sdk. Key changes include: - Updated external repository URLs (zombienet-sdk, parity-db, parity-scale-codec, wasm-instrument) to point to pezkuwichain forks. - Modified internal documentation and code comments to reflect PezkuwiChain naming and structure. - Replaced direct references to with or specific paths within the for XCM, Pezkuwi, and other modules. - Cleaned up deprecated issue and PR references in various and files, particularly in and modules. - Adjusted image and logo URLs in documentation to point to PezkuwiChain assets. - Removed or rephrased comments related to external Polkadot/Substrate PRs and issues. This is a significant step towards fully customizing the SDK for the PezkuwiChain ecosystem.
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
[package]
|
||||
name = "pezsp-wasm-interface"
|
||||
version = "20.0.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license = "Apache-2.0"
|
||||
homepage.workspace = true
|
||||
repository.workspace = true
|
||||
description = "Types and traits for interfacing between the host and the wasm runtime."
|
||||
documentation = "https://docs.rs/pezsp-wasm-interface"
|
||||
readme = "README.md"
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
||||
[dependencies]
|
||||
anyhow = { optional = true, workspace = true }
|
||||
codec = { features = ["derive"], workspace = true }
|
||||
impl-trait-for-tuples = { workspace = true }
|
||||
log = { optional = true, workspace = true, default-features = true }
|
||||
wasmtime = { optional = true, workspace = true }
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
std = ["anyhow?/std", "codec/std", "log/std"]
|
||||
wasmtime = ["anyhow", "dep:wasmtime"]
|
||||
@@ -0,0 +1,3 @@
|
||||
Types and traits for interfacing between the host and the wasm runtime.
|
||||
|
||||
License: Apache-2.0
|
||||
@@ -0,0 +1,630 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! Types and traits for interfacing between the host and the wasm runtime.
|
||||
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::{borrow::Cow, string::String, vec, vec::Vec};
|
||||
use core::{iter::Iterator, marker::PhantomData, mem};
|
||||
|
||||
#[cfg(not(all(feature = "std", feature = "wasmtime")))]
|
||||
#[macro_export]
|
||||
macro_rules! if_wasmtime_is_enabled {
|
||||
($($token:tt)*) => {};
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "std", feature = "wasmtime"))]
|
||||
#[macro_export]
|
||||
macro_rules! if_wasmtime_is_enabled {
|
||||
($($token:tt)*) => {
|
||||
$($token)*
|
||||
}
|
||||
}
|
||||
|
||||
if_wasmtime_is_enabled! {
|
||||
// Reexport wasmtime so that its types are accessible from the procedural macro.
|
||||
pub use wasmtime;
|
||||
|
||||
// Wasmtime uses anyhow types but doesn't reexport them.
|
||||
pub use anyhow;
|
||||
}
|
||||
|
||||
/// Result type used by traits in this crate.
|
||||
pub type Result<T> = core::result::Result<T, String>;
|
||||
|
||||
/// Value types supported by Bizinikiwi on the boundary between host/Wasm.
|
||||
#[derive(Copy, Clone, PartialEq, Debug, Eq)]
|
||||
pub enum ValueType {
|
||||
/// An `i32` value type.
|
||||
I32,
|
||||
/// An `i64` value type.
|
||||
I64,
|
||||
/// An `f32` value type.
|
||||
F32,
|
||||
/// An `f64` value type.
|
||||
F64,
|
||||
}
|
||||
|
||||
impl From<ValueType> for u8 {
|
||||
fn from(val: ValueType) -> u8 {
|
||||
match val {
|
||||
ValueType::I32 => 0,
|
||||
ValueType::I64 => 1,
|
||||
ValueType::F32 => 2,
|
||||
ValueType::F64 => 3,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<u8> for ValueType {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(val: u8) -> core::result::Result<ValueType, ()> {
|
||||
match val {
|
||||
0 => Ok(Self::I32),
|
||||
1 => Ok(Self::I64),
|
||||
2 => Ok(Self::F32),
|
||||
3 => Ok(Self::F64),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Values supported by Bizinikiwi on the boundary between host/Wasm.
|
||||
#[derive(PartialEq, Debug, Clone, Copy, codec::Encode, codec::Decode)]
|
||||
pub enum Value {
|
||||
/// A 32-bit integer.
|
||||
I32(i32),
|
||||
/// A 64-bit integer.
|
||||
I64(i64),
|
||||
/// A 32-bit floating-point number stored as raw bit pattern.
|
||||
///
|
||||
/// You can materialize this value using `f32::from_bits`.
|
||||
F32(u32),
|
||||
/// A 64-bit floating-point number stored as raw bit pattern.
|
||||
///
|
||||
/// You can materialize this value using `f64::from_bits`.
|
||||
F64(u64),
|
||||
}
|
||||
|
||||
impl Value {
|
||||
/// Returns the type of this value.
|
||||
pub fn value_type(&self) -> ValueType {
|
||||
match self {
|
||||
Value::I32(_) => ValueType::I32,
|
||||
Value::I64(_) => ValueType::I64,
|
||||
Value::F32(_) => ValueType::F32,
|
||||
Value::F64(_) => ValueType::F64,
|
||||
}
|
||||
}
|
||||
|
||||
/// Return `Self` as `i32`.
|
||||
pub fn as_i32(&self) -> Option<i32> {
|
||||
match self {
|
||||
Self::I32(val) => Some(*val),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Provides `Sealed` trait to prevent implementing trait `PointerType` and `WasmTy` outside of this
|
||||
/// crate.
|
||||
mod private {
|
||||
pub trait Sealed {}
|
||||
|
||||
impl Sealed for u8 {}
|
||||
impl Sealed for u16 {}
|
||||
impl Sealed for u32 {}
|
||||
impl Sealed for u64 {}
|
||||
|
||||
impl Sealed for i32 {}
|
||||
impl Sealed for i64 {}
|
||||
}
|
||||
|
||||
/// Something that can be wrapped in a wasm `Pointer`.
|
||||
///
|
||||
/// This trait is sealed.
|
||||
pub trait PointerType: Sized + private::Sealed {
|
||||
/// The size of the type in wasm.
|
||||
const SIZE: u32 = mem::size_of::<Self>() as u32;
|
||||
}
|
||||
|
||||
impl PointerType for u8 {}
|
||||
impl PointerType for u16 {}
|
||||
impl PointerType for u32 {}
|
||||
impl PointerType for u64 {}
|
||||
|
||||
/// Type to represent a pointer in wasm at the host.
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct Pointer<T> {
|
||||
ptr: u32,
|
||||
_marker: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T> Copy for Pointer<T> {}
|
||||
impl<T> Clone for Pointer<T> {
|
||||
fn clone(&self) -> Self {
|
||||
Pointer { ptr: self.ptr, _marker: PhantomData }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PointerType> Pointer<T> {
|
||||
/// Create a new instance of `Self`.
|
||||
pub fn new(ptr: u32) -> Self {
|
||||
Self { ptr, _marker: Default::default() }
|
||||
}
|
||||
|
||||
/// Calculate the offset from this pointer.
|
||||
///
|
||||
/// `offset` is in units of `T`. So, `3` means `3 * mem::size_of::<T>()` as offset to the
|
||||
/// pointer.
|
||||
///
|
||||
/// Returns an `Option` to respect that the pointer could probably overflow.
|
||||
pub fn offset(self, offset: u32) -> Option<Self> {
|
||||
offset
|
||||
.checked_mul(T::SIZE)
|
||||
.and_then(|o| self.ptr.checked_add(o))
|
||||
.map(|ptr| Self { ptr, _marker: Default::default() })
|
||||
}
|
||||
|
||||
/// Create a null pointer.
|
||||
pub fn null() -> Self {
|
||||
Self::new(0)
|
||||
}
|
||||
|
||||
/// Cast this pointer of type `T` to a pointer of type `R`.
|
||||
pub fn cast<R: PointerType>(self) -> Pointer<R> {
|
||||
Pointer::new(self.ptr)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PointerType> From<u32> for Pointer<T> {
|
||||
fn from(ptr: u32) -> Self {
|
||||
Pointer::new(ptr)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PointerType> From<Pointer<T>> for u32 {
|
||||
fn from(ptr: Pointer<T>) -> Self {
|
||||
ptr.ptr
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PointerType> From<Pointer<T>> for u64 {
|
||||
fn from(ptr: Pointer<T>) -> Self {
|
||||
u64::from(ptr.ptr)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PointerType> From<Pointer<T>> for usize {
|
||||
fn from(ptr: Pointer<T>) -> Self {
|
||||
ptr.ptr as _
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PointerType> IntoValue for Pointer<T> {
|
||||
const VALUE_TYPE: ValueType = ValueType::I32;
|
||||
fn into_value(self) -> Value {
|
||||
Value::I32(self.ptr as _)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PointerType> TryFromValue for Pointer<T> {
|
||||
fn try_from_value(val: Value) -> Option<Self> {
|
||||
match val {
|
||||
Value::I32(val) => Some(Self::new(val as _)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The word size used in wasm. Normally known as `usize` in Rust.
|
||||
pub type WordSize = u32;
|
||||
|
||||
/// The Signature of a function
|
||||
#[derive(Eq, PartialEq, Debug, Clone)]
|
||||
pub struct Signature {
|
||||
/// The arguments of a function.
|
||||
pub args: Cow<'static, [ValueType]>,
|
||||
/// The optional return value of a function.
|
||||
pub return_value: Option<ValueType>,
|
||||
}
|
||||
|
||||
impl Signature {
|
||||
/// Create a new instance of `Signature`.
|
||||
pub fn new<T: Into<Cow<'static, [ValueType]>>>(
|
||||
args: T,
|
||||
return_value: Option<ValueType>,
|
||||
) -> Self {
|
||||
Self { args: args.into(), return_value }
|
||||
}
|
||||
|
||||
/// Create a new instance of `Signature` with the given `args` and without any return value.
|
||||
pub fn new_with_args<T: Into<Cow<'static, [ValueType]>>>(args: T) -> Self {
|
||||
Self { args: args.into(), return_value: None }
|
||||
}
|
||||
}
|
||||
|
||||
/// A trait that requires `RefUnwindSafe` when `feature = std`.
|
||||
#[cfg(feature = "std")]
|
||||
pub trait MaybeRefUnwindSafe: std::panic::RefUnwindSafe {}
|
||||
#[cfg(feature = "std")]
|
||||
impl<T: std::panic::RefUnwindSafe> MaybeRefUnwindSafe for T {}
|
||||
|
||||
/// A trait that requires `RefUnwindSafe` when `feature = std`.
|
||||
#[cfg(not(feature = "std"))]
|
||||
pub trait MaybeRefUnwindSafe {}
|
||||
#[cfg(not(feature = "std"))]
|
||||
impl<T> MaybeRefUnwindSafe for T {}
|
||||
|
||||
/// Something that provides a function implementation on the host for a wasm function.
|
||||
pub trait Function: MaybeRefUnwindSafe + Send + Sync {
|
||||
/// Returns the name of this function.
|
||||
fn name(&self) -> &str;
|
||||
/// Returns the signature of this function.
|
||||
fn signature(&self) -> Signature;
|
||||
/// Execute this function with the given arguments.
|
||||
fn execute(
|
||||
&self,
|
||||
context: &mut dyn FunctionContext,
|
||||
args: &mut dyn Iterator<Item = Value>,
|
||||
) -> Result<Option<Value>>;
|
||||
}
|
||||
|
||||
impl PartialEq for dyn Function {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
other.name() == self.name() && other.signature() == self.signature()
|
||||
}
|
||||
}
|
||||
|
||||
/// Context used by `Function` to interact with the allocator and the memory of the wasm instance.
|
||||
pub trait FunctionContext {
|
||||
/// Read memory from `address` into a vector.
|
||||
fn read_memory(&self, address: Pointer<u8>, size: WordSize) -> Result<Vec<u8>> {
|
||||
let mut vec = vec![0; size as usize];
|
||||
self.read_memory_into(address, &mut vec)?;
|
||||
Ok(vec)
|
||||
}
|
||||
/// Read memory into the given `dest` buffer from `address`.
|
||||
fn read_memory_into(&self, address: Pointer<u8>, dest: &mut [u8]) -> Result<()>;
|
||||
/// Write the given data at `address` into the memory.
|
||||
fn write_memory(&mut self, address: Pointer<u8>, data: &[u8]) -> Result<()>;
|
||||
/// Allocate a memory instance of `size` bytes.
|
||||
fn allocate_memory(&mut self, size: WordSize) -> Result<Pointer<u8>>;
|
||||
/// Deallocate a given memory instance.
|
||||
fn deallocate_memory(&mut self, ptr: Pointer<u8>) -> Result<()>;
|
||||
/// Registers a panic error message within the executor.
|
||||
///
|
||||
/// This is meant to be used in situations where the runtime
|
||||
/// encounters an unrecoverable error and intends to panic.
|
||||
///
|
||||
/// Panicking in WASM is done through the [`unreachable`](https://webassembly.github.io/spec/core/syntax/instructions.html#syntax-instr-control)
|
||||
/// instruction which causes an unconditional trap and immediately aborts
|
||||
/// the execution. It does not however allow for any diagnostics to be
|
||||
/// passed through to the host, so while we do know that *something* went
|
||||
/// wrong we don't have any direct indication of what *exactly* went wrong.
|
||||
///
|
||||
/// As a workaround we use this method right before the execution is
|
||||
/// actually aborted to pass an error message to the host so that it
|
||||
/// can associate it with the next trap, and return that to the caller.
|
||||
///
|
||||
/// A WASM trap should be triggered immediately after calling this method;
|
||||
/// otherwise the error message might be associated with a completely
|
||||
/// unrelated trap.
|
||||
///
|
||||
/// It should only be called once, however calling it more than once
|
||||
/// is harmless and will overwrite the previously set error message.
|
||||
fn register_panic_error_message(&mut self, message: &str);
|
||||
}
|
||||
|
||||
if_wasmtime_is_enabled! {
|
||||
/// A trait used to statically register host callbacks with the WASM executor,
|
||||
/// so that they call be called from within the runtime with minimal overhead.
|
||||
///
|
||||
/// This is used internally to interface the wasmtime-based executor with the
|
||||
/// host functions' definitions generated through the runtime interface macro,
|
||||
/// and is not meant to be used directly.
|
||||
pub trait HostFunctionRegistry {
|
||||
type State: 'static;
|
||||
type Error;
|
||||
type FunctionContext: FunctionContext;
|
||||
|
||||
/// Wraps the given `caller` in a type which implements `FunctionContext`
|
||||
/// and calls the given `callback`.
|
||||
fn with_function_context<R>(
|
||||
caller: wasmtime::Caller<Self::State>,
|
||||
callback: impl FnOnce(&mut dyn FunctionContext) -> R,
|
||||
) -> R;
|
||||
|
||||
/// Registers a given host function with the WASM executor.
|
||||
///
|
||||
/// The function has to be statically callable, and all of its arguments
|
||||
/// and its return value have to be compatible with WASM FFI.
|
||||
fn register_static<Params, Results>(
|
||||
&mut self,
|
||||
fn_name: &str,
|
||||
func: impl wasmtime::IntoFunc<Self::State, Params, Results> + 'static,
|
||||
) -> core::result::Result<(), Self::Error>;
|
||||
}
|
||||
}
|
||||
|
||||
/// Something that provides implementations for host functions.
|
||||
pub trait HostFunctions: 'static + Send + Sync {
|
||||
/// Returns the host functions `Self` provides.
|
||||
fn host_functions() -> Vec<&'static dyn Function>;
|
||||
|
||||
if_wasmtime_is_enabled! {
|
||||
/// Statically registers the host functions.
|
||||
fn register_static<T>(registry: &mut T) -> core::result::Result<(), T::Error>
|
||||
where
|
||||
T: HostFunctionRegistry;
|
||||
}
|
||||
}
|
||||
|
||||
#[impl_trait_for_tuples::impl_for_tuples(30)]
|
||||
impl HostFunctions for Tuple {
|
||||
fn host_functions() -> Vec<&'static dyn Function> {
|
||||
let mut host_functions = Vec::new();
|
||||
|
||||
for_tuples!( #( host_functions.extend(Tuple::host_functions()); )* );
|
||||
|
||||
host_functions
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "std", feature = "wasmtime"))]
|
||||
fn register_static<T>(registry: &mut T) -> core::result::Result<(), T::Error>
|
||||
where
|
||||
T: HostFunctionRegistry,
|
||||
{
|
||||
for_tuples!(
|
||||
#( Tuple::register_static(registry)?; )*
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// A wrapper which merges two sets of host functions, and allows the second set to override
|
||||
/// the host functions from the first set.
|
||||
pub struct ExtendedHostFunctions<Base, Overlay> {
|
||||
phantom: PhantomData<(Base, Overlay)>,
|
||||
}
|
||||
|
||||
impl<Base, Overlay> HostFunctions for ExtendedHostFunctions<Base, Overlay>
|
||||
where
|
||||
Base: HostFunctions,
|
||||
Overlay: HostFunctions,
|
||||
{
|
||||
fn host_functions() -> Vec<&'static dyn Function> {
|
||||
let mut base = Base::host_functions();
|
||||
let overlay = Overlay::host_functions();
|
||||
base.retain(|host_fn| {
|
||||
!overlay.iter().any(|ext_host_fn| host_fn.name() == ext_host_fn.name())
|
||||
});
|
||||
base.extend(overlay);
|
||||
base
|
||||
}
|
||||
|
||||
if_wasmtime_is_enabled! {
|
||||
fn register_static<T>(registry: &mut T) -> core::result::Result<(), T::Error>
|
||||
where
|
||||
T: HostFunctionRegistry,
|
||||
{
|
||||
struct Proxy<'a, T> {
|
||||
registry: &'a mut T,
|
||||
seen_overlay: std::collections::HashSet<String>,
|
||||
seen_base: std::collections::HashSet<String>,
|
||||
overlay_registered: bool,
|
||||
}
|
||||
|
||||
impl<'a, T> HostFunctionRegistry for Proxy<'a, T>
|
||||
where
|
||||
T: HostFunctionRegistry,
|
||||
{
|
||||
type State = T::State;
|
||||
type Error = T::Error;
|
||||
type FunctionContext = T::FunctionContext;
|
||||
|
||||
fn with_function_context<R>(
|
||||
caller: wasmtime::Caller<Self::State>,
|
||||
callback: impl FnOnce(&mut dyn FunctionContext) -> R,
|
||||
) -> R {
|
||||
T::with_function_context(caller, callback)
|
||||
}
|
||||
|
||||
fn register_static<Params, Results>(
|
||||
&mut self,
|
||||
fn_name: &str,
|
||||
func: impl wasmtime::IntoFunc<Self::State, Params, Results> + 'static,
|
||||
) -> core::result::Result<(), Self::Error> {
|
||||
if self.overlay_registered {
|
||||
if !self.seen_base.insert(fn_name.to_owned()) {
|
||||
log::warn!(
|
||||
target: "extended_host_functions",
|
||||
"Duplicate base host function: '{}'",
|
||||
fn_name,
|
||||
);
|
||||
|
||||
// TODO: Return an error here?
|
||||
return Ok(())
|
||||
}
|
||||
|
||||
if self.seen_overlay.contains(fn_name) {
|
||||
// Was already registered when we went through the overlay, so just ignore it.
|
||||
log::debug!(
|
||||
target: "extended_host_functions",
|
||||
"Overriding base host function: '{}'",
|
||||
fn_name,
|
||||
);
|
||||
|
||||
return Ok(())
|
||||
}
|
||||
} else if !self.seen_overlay.insert(fn_name.to_owned()) {
|
||||
log::warn!(
|
||||
target: "extended_host_functions",
|
||||
"Duplicate overlay host function: '{}'",
|
||||
fn_name,
|
||||
);
|
||||
|
||||
// TODO: Return an error here?
|
||||
return Ok(())
|
||||
}
|
||||
|
||||
self.registry.register_static(fn_name, func)
|
||||
}
|
||||
}
|
||||
|
||||
let mut proxy = Proxy {
|
||||
registry,
|
||||
seen_overlay: Default::default(),
|
||||
seen_base: Default::default(),
|
||||
overlay_registered: false,
|
||||
};
|
||||
|
||||
// The functions from the `Overlay` can override those from the `Base`,
|
||||
// so `Overlay` is registered first, and then we skip those functions
|
||||
// in `Base` if they were already registered from the `Overlay`.
|
||||
Overlay::register_static(&mut proxy)?;
|
||||
proxy.overlay_registered = true;
|
||||
Base::register_static(&mut proxy)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A trait for types directly usable at the WASM FFI boundary without any conversion at all.
|
||||
///
|
||||
/// This trait is sealed and should not be implemented downstream.
|
||||
#[cfg(all(feature = "std", feature = "wasmtime"))]
|
||||
pub trait WasmTy: wasmtime::WasmTy + private::Sealed {}
|
||||
|
||||
/// A trait for types directly usable at the WASM FFI boundary without any conversion at all.
|
||||
///
|
||||
/// This trait is sealed and should not be implemented downstream.
|
||||
#[cfg(not(all(feature = "std", feature = "wasmtime")))]
|
||||
pub trait WasmTy: private::Sealed {}
|
||||
|
||||
impl WasmTy for i32 {}
|
||||
impl WasmTy for u32 {}
|
||||
impl WasmTy for i64 {}
|
||||
impl WasmTy for u64 {}
|
||||
|
||||
/// Something that can be converted into a wasm compatible `Value`.
|
||||
pub trait IntoValue {
|
||||
/// The type of the value in wasm.
|
||||
const VALUE_TYPE: ValueType;
|
||||
|
||||
/// Convert `self` into a wasm `Value`.
|
||||
fn into_value(self) -> Value;
|
||||
}
|
||||
|
||||
/// Something that can may be created from a wasm `Value`.
|
||||
pub trait TryFromValue: Sized {
|
||||
/// Try to convert the given `Value` into `Self`.
|
||||
fn try_from_value(val: Value) -> Option<Self>;
|
||||
}
|
||||
|
||||
macro_rules! impl_into_and_from_value {
|
||||
(
|
||||
$(
|
||||
$type:ty, $( < $gen:ident >, )? $value_variant:ident,
|
||||
)*
|
||||
) => {
|
||||
$(
|
||||
impl $( <$gen> )? IntoValue for $type {
|
||||
const VALUE_TYPE: ValueType = ValueType::$value_variant;
|
||||
fn into_value(self) -> Value { Value::$value_variant(self as _) }
|
||||
}
|
||||
|
||||
impl $( <$gen> )? TryFromValue for $type {
|
||||
fn try_from_value(val: Value) -> Option<Self> {
|
||||
match val {
|
||||
Value::$value_variant(val) => Some(val as _),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
impl_into_and_from_value! {
|
||||
u8, I32,
|
||||
u16, I32,
|
||||
u32, I32,
|
||||
u64, I64,
|
||||
i8, I32,
|
||||
i16, I32,
|
||||
i32, I32,
|
||||
i64, I64,
|
||||
}
|
||||
|
||||
/// Typed value that can be returned from a function.
|
||||
///
|
||||
/// Basically a `TypedValue` plus `Unit`, for functions which return nothing.
|
||||
#[derive(Clone, Copy, PartialEq, codec::Encode, codec::Decode, Debug)]
|
||||
pub enum ReturnValue {
|
||||
/// For returning nothing.
|
||||
Unit,
|
||||
/// For returning some concrete value.
|
||||
Value(Value),
|
||||
}
|
||||
|
||||
impl From<Value> for ReturnValue {
|
||||
fn from(v: Value) -> ReturnValue {
|
||||
ReturnValue::Value(v)
|
||||
}
|
||||
}
|
||||
|
||||
impl ReturnValue {
|
||||
/// Maximum number of bytes `ReturnValue` might occupy when serialized with `SCALE`.
|
||||
///
|
||||
/// Breakdown:
|
||||
/// 1 byte for encoding unit/value variant
|
||||
/// 1 byte for encoding value type
|
||||
/// 8 bytes for encoding the biggest value types available in wasm: f64, i64.
|
||||
pub const ENCODED_MAX_SIZE: usize = 10;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use codec::Encode;
|
||||
|
||||
#[test]
|
||||
fn pointer_offset_works() {
|
||||
let ptr = Pointer::<u32>::null();
|
||||
|
||||
assert_eq!(ptr.offset(10).unwrap(), Pointer::new(40));
|
||||
assert_eq!(ptr.offset(32).unwrap(), Pointer::new(128));
|
||||
|
||||
let ptr = Pointer::<u64>::null();
|
||||
|
||||
assert_eq!(ptr.offset(10).unwrap(), Pointer::new(80));
|
||||
assert_eq!(ptr.offset(32).unwrap(), Pointer::new(256));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn return_value_encoded_max_size() {
|
||||
let encoded = ReturnValue::Value(Value::I64(-1)).encode();
|
||||
assert_eq!(encoded.len(), ReturnValue::ENCODED_MAX_SIZE);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user