Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Commit

Permalink
Support u128/i128 in runtime interface (#4703)
Browse files Browse the repository at this point in the history
* Support `u128`/`i128` in runtime interface

This implements support for `u128`/`i128` as parameters/return value in
runtime interfaces. As we can not pass them as identity, as for the
other primitives types, we pass them as an pointer to an `[u8; 16]` array.

* Remove some unsafe code usage
  • Loading branch information
bkchr authored Jan 22, 2020
1 parent cf020ad commit ef578cd
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 0 deletions.
52 changes: 52 additions & 0 deletions primitives/runtime-interface/src/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -471,3 +471,55 @@ impl<T: sp_wasm_interface::PointerType> IntoFFIValue for Pointer<T> {
Ok(self.into())
}
}

/// Implement the traits for `u128`/`i128`
macro_rules! for_u128_i128 {
($type:ty) => {
/// `u128`/`i128` is passed as `u32`.
///
/// The `u32` is a pointer to an `[u8; 16]` array.
impl RIType for $type {
type FFIType = u32;
}

#[cfg(not(feature = "std"))]
impl IntoFFIValue for $type {
type Owned = ();

fn into_ffi_value(&self) -> WrappedFFIValue<u32> {
unsafe { (mem::transmute::<&Self, *const u8>(self) as u32).into() }
}
}

#[cfg(not(feature = "std"))]
impl FromFFIValue for $type {
fn from_ffi_value(arg: u32) -> $type {
<$type>::from_le_bytes(<[u8; mem::size_of::<$type>()]>::from_ffi_value(arg))
}
}

#[cfg(feature = "std")]
impl FromFFIValue for $type {
type SelfInstance = $type;

fn from_ffi_value(context: &mut dyn FunctionContext, arg: u32) -> Result<$type> {
let data = context.read_memory(Pointer::new(arg), mem::size_of::<$type>() as u32)?;
let mut res = [0u8; mem::size_of::<$type>()];
res.copy_from_slice(&data);
Ok(<$type>::from_le_bytes(res))
}
}

#[cfg(feature = "std")]
impl IntoFFIValue for $type {
fn into_ffi_value(self, context: &mut dyn FunctionContext) -> Result<u32> {
let addr = context.allocate_memory(mem::size_of::<$type>() as u32)?;
context.write_memory(addr, &self.to_le_bytes())?;
Ok(addr.into())
}
}
}
}

for_u128_i128!(u128);
for_u128_i128!(i128);
3 changes: 3 additions & 0 deletions primitives/runtime-interface/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,12 @@
//! | `u16` | `u16` | `Identity` |
//! | `u32` | `u32` | `Identity` |
//! | `u64` | `u64` | `Identity` |
//! | `i128` | `u32` | `v.as_ptr()` (pointer to a 16 byte array) |
//! | `i8` | `i8` | `Identity` |
//! | `i16` | `i16` | `Identity` |
//! | `i32` | `i32` | `Identity` |
//! | `i64` | `i64` | `Identity` |
//! | `u128` | `u32` | `v.as_ptr()` (pointer to a 16 byte array) |
//! | `bool` | `u8` | `if v { 1 } else { 0 }` |
//! | `&str` | `u64` | <code>v.len() 32bit << 32 &#124; v.as_ptr() 32bit</code> |
//! | `&[u8]` | `u64` | <code>v.len() 32bit << 32 &#124; v.as_ptr() 32bit</code> |
Expand All @@ -93,6 +95,7 @@
//! | `&[T] where T: Encode` | `u64` | `let e = v.encode();`<br><br><code>e.len() 32bit << 32 &#124; e.as_ptr() 32bit</code> |
//! | `[u8; N]` | `u32` | `v.as_ptr()` |
//! | `*const T` | `u32` | `Identity` |
//! | `Option<T>` | `u64` | `let e = v.encode();`<br><br><code>e.len() 32bit << 32 &#124; e.as_ptr() 32bit</code> |
//! | [`T where T: PassBy<PassBy=Inner>`](pass_by::Inner) | Depends on inner | Depends on inner |
//! | [`T where T: PassBy<PassBy=Codec>`](pass_by::Codec) | `u64`| <code>v.len() 32bit << 32 &#124; v.as_ptr() 32bit</code> |
//!
Expand Down
20 changes: 20 additions & 0 deletions primitives/runtime-interface/test-wasm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,16 @@ pub trait TestApi {
fn overwrite_native_function_implementation() -> bool {
false
}

/// Gets an `u128` and returns this value
fn get_and_return_u128(val: u128) -> u128 {
val
}

/// Gets an `i128` and returns this value
fn get_and_return_i128(val: i128) -> i128 {
val
}
}

/// Two random external functions from the old runtime interface.
Expand Down Expand Up @@ -191,4 +201,14 @@ wasm_export_functions! {

assert!(test_api::overwrite_native_function_implementation());
}

fn test_u128_i128_as_parameter_and_return_value() {
for val in &[u128::max_value(), 1u128, 5000u128, u64::max_value() as u128] {
assert_eq!(*val, test_api::get_and_return_u128(*val));
}

for val in &[i128::max_value(), i128::min_value(), 1i128, 5000i128, u64::max_value() as i128] {
assert_eq!(*val, test_api::get_and_return_i128(*val));
}
}
}
5 changes: 5 additions & 0 deletions primitives/runtime-interface/test/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,3 +108,8 @@ fn test_invalid_utf8_data_should_return_an_error() {
fn test_overwrite_native_function_implementation() {
call_wasm_method::<HostFunctions>("test_overwrite_native_function_implementation");
}

#[test]
fn test_u128_i128_as_parameter_and_return_value() {
call_wasm_method::<HostFunctions>("test_u128_i128_as_parameter_and_return_value");
}

0 comments on commit ef578cd

Please sign in to comment.