Skip to content

Commit

Permalink
Merge #1624
Browse files Browse the repository at this point in the history
1624: Add Value::I32/Value::I64 converters from unsigned ints r=MarkMcCaskey a=webmaster128

# Description

Allow conversion of Rust `u32`/`u64` to Wasm `i32`/`i64` (which is something different than Rust's `i32`/`i64`.

At https://github.com/sunfishcode/wasm-reference-manual/blob/master/WebAssembly.md you see how i32/i64 are used to store both signed and unsigned values and are intepreted based in the operation.

All our imports and exports

```rust
// imports

extern "C" {
    fn db_read(key: u32) -> u32;
    fn db_write(key: u32, value: u32);
    fn db_remove(key: u32);

     // …
}

// exports
/// allocate reserves the given number of bytes in wasm memory and returns a pointer
/// to a Region defining this data. This space is managed by the calling process
/// and should be accompanied by a corresponding deallocate
#[no_mangle]
extern "C" fn allocate(size: usize) -> u32 {
    alloc(size) as u32
}

/// deallocate expects a pointer to a Region created with allocate.
/// It will free both the Region and the memory referenced by the Region.
#[no_mangle]
extern "C" fn deallocate(pointer: u32) {
    // auto-drop Region on function end
    let _ = unsafe { consume_region(pointer as *mut Region) };
}

// ...
```

compile from Rust `u32` to Wasm `i32`.

I hope this is the right approach work with those flexible Wasm types. Let me know what you think.

# Review

- [ ] Add a short description of the the change to the CHANGELOG.md file


Co-authored-by: Simon Warta <[email protected]>
  • Loading branch information
bors[bot] and webmaster128 authored Oct 12, 2020
2 parents bb9149b + 5cc8439 commit 038af91
Showing 1 changed file with 63 additions and 2 deletions.
65 changes: 63 additions & 2 deletions lib/wasmer-types/src/values.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,14 @@ use crate::types::Type;
/// produce.
#[derive(Clone, PartialEq)]
pub enum Value<T> {
/// A 32-bit integer
/// A 32-bit integer.
///
/// In Wasm integers are sign-agnostic, i.e. this can either be signed or unsigned.
I32(i32),

/// A 64-bit integer
/// A 64-bit integer.
///
/// In Wasm integers are sign-agnostic, i.e. this can either be signed or unsigned.
I64(i64),

/// A 32-bit float.
Expand Down Expand Up @@ -175,12 +179,26 @@ impl<T> From<i32> for Value<T> {
}
}

impl<T> From<u32> for Value<T> {
fn from(val: u32) -> Self {
// In Wasm integers are sign-agnostic, so i32 is basically a 4 byte storage we can use for signed or unsigned 32-bit integers.
Self::I32(val as i32)
}
}

impl<T> From<i64> for Value<T> {
fn from(val: i64) -> Self {
Self::I64(val)
}
}

impl<T> From<u64> for Value<T> {
fn from(val: u64) -> Self {
// In Wasm integers are sign-agnostic, so i64 is basically an 8 byte storage we can use for signed or unsigned 64-bit integers.
Self::I64(val as i64)
}
}

impl<T> From<f32> for Value<T> {
fn from(val: f32) -> Self {
Self::F32(val)
Expand All @@ -204,3 +222,46 @@ impl<T> From<ExternRef> for Value<T> {
// Self::FuncRef(val)
// }
// }

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_value_i32_from_u32() {
let bytes = [0x00, 0x00, 0x00, 0x00];
let v = Value::<()>::from(u32::from_be_bytes(bytes.clone()));
assert_eq!(v, Value::I32(i32::from_be_bytes(bytes.clone())));

let bytes = [0x00, 0x00, 0x00, 0x01];
let v = Value::<()>::from(u32::from_be_bytes(bytes.clone()));
assert_eq!(v, Value::I32(i32::from_be_bytes(bytes.clone())));

let bytes = [0xAA, 0xBB, 0xCC, 0xDD];
let v = Value::<()>::from(u32::from_be_bytes(bytes.clone()));
assert_eq!(v, Value::I32(i32::from_be_bytes(bytes.clone())));

let bytes = [0xFF, 0xFF, 0xFF, 0xFF];
let v = Value::<()>::from(u32::from_be_bytes(bytes.clone()));
assert_eq!(v, Value::I32(i32::from_be_bytes(bytes.clone())));
}

#[test]
fn test_value_i64_from_u64() {
let bytes = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
let v = Value::<()>::from(u64::from_be_bytes(bytes.clone()));
assert_eq!(v, Value::I64(i64::from_be_bytes(bytes.clone())));

let bytes = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01];
let v = Value::<()>::from(u64::from_be_bytes(bytes.clone()));
assert_eq!(v, Value::I64(i64::from_be_bytes(bytes.clone())));

let bytes = [0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x00, 0x11];
let v = Value::<()>::from(u64::from_be_bytes(bytes.clone()));
assert_eq!(v, Value::I64(i64::from_be_bytes(bytes.clone())));

let bytes = [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF];
let v = Value::<()>::from(u64::from_be_bytes(bytes.clone()));
assert_eq!(v, Value::I64(i64::from_be_bytes(bytes.clone())));
}
}

0 comments on commit 038af91

Please sign in to comment.