Tweak the API of the Val type (#679)
* Tweak the API of the `Val` type A few updates to the API of the `Val` type: * Added a payload for `V128`. * Replace existing accessor methods with `Option`-returning versions. * Add `unwrap_xxx` family of methods to extract a value and panic. * Remove `Into` conversions which panic, since panicking in `From` or `Into` isn't idiomatic in Rust * Add documentation to all methods/values/enums/etc. * Rename `Val::default` to `Val::null` * Run rustfmt * Review comments
This commit is contained in:
@@ -148,7 +148,7 @@ impl Func {
|
||||
}
|
||||
|
||||
pub fn call(&self, params: &[Val]) -> Result<Box<[Val]>, HostRef<Trap>> {
|
||||
let mut results = vec![Val::default(); self.result_arity()];
|
||||
let mut results = vec![Val::null(); self.result_arity()];
|
||||
self.callable.call(params, &mut results)?;
|
||||
Ok(results.into_boxed_slice())
|
||||
}
|
||||
@@ -215,8 +215,8 @@ impl Global {
|
||||
match self.r#type().content() {
|
||||
ValType::I32 => Val::from(*definition.as_i32()),
|
||||
ValType::I64 => Val::from(*definition.as_i64()),
|
||||
ValType::F32 => Val::from_f32_bits(*definition.as_u32()),
|
||||
ValType::F64 => Val::from_f64_bits(*definition.as_u64()),
|
||||
ValType::F32 => Val::F32(*definition.as_u32()),
|
||||
ValType::F64 => Val::F64(*definition.as_u64()),
|
||||
_ => unimplemented!("Global::get for {:?}", self.r#type().content()),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ unsafe extern "C" fn stub_fn(vmctx: *mut VMContext, call_id: u32, values_vec: *m
|
||||
(args, signature.returns.len())
|
||||
};
|
||||
|
||||
let mut returns = vec![Val::default(); returns_len];
|
||||
let mut returns = vec![Val::null(); returns_len];
|
||||
let func = &instance
|
||||
.host_state()
|
||||
.downcast_mut::<TrampolineState>()
|
||||
|
||||
@@ -6,21 +6,71 @@ use std::ptr;
|
||||
use wasmtime_environ::ir;
|
||||
use wasmtime_jit::RuntimeValue;
|
||||
|
||||
/// Possible runtime values that a WebAssembly module can either consume or
|
||||
/// produce.
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Val {
|
||||
/// A 32-bit integer
|
||||
I32(i32),
|
||||
|
||||
/// A 64-bit integer
|
||||
I64(i64),
|
||||
|
||||
/// A 32-bit float.
|
||||
///
|
||||
/// Note that the raw bits of the float are stored here, and you can use
|
||||
/// `f32::from_bits` to create an `f32` value.
|
||||
F32(u32),
|
||||
|
||||
/// A 64-bit float.
|
||||
///
|
||||
/// Note that the raw bits of the float are stored here, and you can use
|
||||
/// `f64::from_bits` to create an `f64` value.
|
||||
F64(u64),
|
||||
|
||||
/// An `anyref` value which can hold opaque data to the wasm instance itself.
|
||||
///
|
||||
/// Note that this is a nullable value as well.
|
||||
AnyRef(AnyRef),
|
||||
|
||||
/// A first-class reference to a WebAssembly function.
|
||||
FuncRef(HostRef<Func>),
|
||||
|
||||
/// A 128-bit number
|
||||
V128([u8; 16]),
|
||||
}
|
||||
|
||||
macro_rules! accessors {
|
||||
($bind:ident $(($variant:ident($ty:ty) $get:ident $unwrap:ident $cvt:expr))*) => ($(
|
||||
/// Attempt to access the underlying value of this `Val`, returning
|
||||
/// `None` if it is not the correct type.
|
||||
pub fn $get(&self) -> Option<$ty> {
|
||||
if let Val::$variant($bind) = self {
|
||||
Some($cvt)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the underlying value of this `Val`, panicking if it's the
|
||||
/// wrong type.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if `self` is not of the right type.
|
||||
pub fn $unwrap(&self) -> $ty {
|
||||
self.$get().expect(concat!("expected ", stringify!($ty)))
|
||||
}
|
||||
)*)
|
||||
}
|
||||
|
||||
impl Val {
|
||||
pub fn default() -> Val {
|
||||
/// Returns a null `anyref` value.
|
||||
pub fn null() -> Val {
|
||||
Val::AnyRef(AnyRef::null())
|
||||
}
|
||||
|
||||
/// Returns the corresponding [`ValType`] for this `Val`.
|
||||
pub fn r#type(&self) -> ValType {
|
||||
match self {
|
||||
Val::I32(_) => ValType::I32,
|
||||
@@ -29,6 +79,7 @@ impl Val {
|
||||
Val::F64(_) => ValType::F64,
|
||||
Val::AnyRef(_) => ValType::AnyRef,
|
||||
Val::FuncRef(_) => ValType::FuncRef,
|
||||
Val::V128(_) => ValType::V128,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,52 +103,36 @@ impl Val {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_f32_bits(v: u32) -> Val {
|
||||
Val::F32(v)
|
||||
accessors! {
|
||||
e
|
||||
(I32(i32) i32 unwrap_i32 *e)
|
||||
(I64(i64) i64 unwrap_i64 *e)
|
||||
(F32(f32) f32 unwrap_f32 f32::from_bits(*e))
|
||||
(F64(f64) f64 unwrap_f64 f64::from_bits(*e))
|
||||
(FuncRef(&HostRef<Func>) funcref unwrap_funcref e)
|
||||
(V128(&[u8; 16]) v128 unwrap_v128 e)
|
||||
}
|
||||
|
||||
pub fn from_f64_bits(v: u64) -> Val {
|
||||
Val::F64(v)
|
||||
}
|
||||
|
||||
pub fn i32(&self) -> i32 {
|
||||
if let Val::I32(i) = self {
|
||||
*i
|
||||
} else {
|
||||
panic!("Invalid conversion of {:?} to i32.", self);
|
||||
/// Attempt to access the underlying value of this `Val`, returning
|
||||
/// `None` if it is not the correct type.
|
||||
///
|
||||
/// This will return `Some` for both the `AnyRef` and `FuncRef` types.
|
||||
pub fn anyref(&self) -> Option<AnyRef> {
|
||||
match self {
|
||||
Val::AnyRef(e) => Some(e.clone()),
|
||||
Val::FuncRef(e) => Some(e.anyref()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn i64(&self) -> i64 {
|
||||
if let Val::I64(i) = self {
|
||||
*i
|
||||
} else {
|
||||
panic!("Invalid conversion of {:?} to i64.", self);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn f32(&self) -> f32 {
|
||||
RuntimeValue::F32(self.f32_bits()).unwrap_f32()
|
||||
}
|
||||
|
||||
pub fn f64(&self) -> f64 {
|
||||
RuntimeValue::F64(self.f64_bits()).unwrap_f64()
|
||||
}
|
||||
|
||||
pub fn f32_bits(&self) -> u32 {
|
||||
if let Val::F32(i) = self {
|
||||
*i
|
||||
} else {
|
||||
panic!("Invalid conversion of {:?} to f32.", self);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn f64_bits(&self) -> u64 {
|
||||
if let Val::F64(i) = self {
|
||||
*i
|
||||
} else {
|
||||
panic!("Invalid conversion of {:?} to f64.", self);
|
||||
}
|
||||
/// Returns the underlying value of this `Val`, panicking if it's the
|
||||
/// wrong type.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if `self` is not of the right type.
|
||||
pub fn unwrap_anyref(&self) -> AnyRef {
|
||||
self.anyref().expect("expected anyref")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,30 +160,6 @@ impl From<f64> for Val {
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<i32> for Val {
|
||||
fn into(self) -> i32 {
|
||||
self.i32()
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<i64> for Val {
|
||||
fn into(self) -> i64 {
|
||||
self.i64()
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<f32> for Val {
|
||||
fn into(self) -> f32 {
|
||||
self.f32()
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<f64> for Val {
|
||||
fn into(self) -> f64 {
|
||||
self.f64()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<AnyRef> for Val {
|
||||
fn from(val: AnyRef) -> Val {
|
||||
match &val {
|
||||
@@ -170,16 +181,6 @@ impl From<HostRef<Func>> for Val {
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<AnyRef> for Val {
|
||||
fn into(self) -> AnyRef {
|
||||
match self {
|
||||
Val::AnyRef(r) => r,
|
||||
Val::FuncRef(f) => f.anyref(),
|
||||
_ => panic!("Invalid conversion of {:?} to anyref.", self),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RuntimeValue> for Val {
|
||||
fn from(rv: RuntimeValue) -> Self {
|
||||
match rv {
|
||||
@@ -187,23 +188,7 @@ impl From<RuntimeValue> for Val {
|
||||
RuntimeValue::I64(i) => Val::I64(i),
|
||||
RuntimeValue::F32(u) => Val::F32(u),
|
||||
RuntimeValue::F64(u) => Val::F64(u),
|
||||
x => {
|
||||
panic!("unsupported {:?}", x);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<RuntimeValue> for Val {
|
||||
fn into(self) -> RuntimeValue {
|
||||
match self {
|
||||
Val::I32(i) => RuntimeValue::I32(i),
|
||||
Val::I64(i) => RuntimeValue::I64(i),
|
||||
Val::F32(u) => RuntimeValue::F32(u),
|
||||
Val::F64(u) => RuntimeValue::F64(u),
|
||||
x => {
|
||||
panic!("unsupported {:?}", x);
|
||||
}
|
||||
RuntimeValue::V128(u) => Val::V128(u),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1553,7 +1553,11 @@ unsafe fn into_funcref(val: Val) -> *mut wasm_ref_t {
|
||||
if let Val::AnyRef(AnyRef::Null) = val {
|
||||
return ptr::null_mut();
|
||||
}
|
||||
let r = Box::new(wasm_ref_t { r: val.into() });
|
||||
let anyref = match val.anyref() {
|
||||
Some(anyref) => anyref,
|
||||
None => return ptr::null_mut(),
|
||||
};
|
||||
let r = Box::new(wasm_ref_t { r: anyref });
|
||||
Box::into_raw(r)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user