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

Support u128/i128 in runtime interface #4703

Merged
merged 2 commits into from
Jan 22, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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");
}