From 557785fe129bccbb7edc63408ef7a70bfab15bb0 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Mon, 1 Feb 2021 19:45:13 +0000 Subject: [PATCH] rust: add TypedExecutionResult which allows returning TypedValues --- bindings/rust/src/lib.rs | 123 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 116 insertions(+), 7 deletions(-) diff --git a/bindings/rust/src/lib.rs b/bindings/rust/src/lib.rs index 4d32d9d5d..cffdefb1a 100644 --- a/bindings/rust/src/lib.rs +++ b/bindings/rust/src/lib.rs @@ -218,6 +218,36 @@ impl ExecutionResult { } } +/// The result of an execution. +pub struct TypedExecutionResult { + result: sys::FizzyExecutionResult, + value_type: sys::FizzyValueType, +} + +impl TypedExecutionResult { + /// True if execution has resulted in a trap. + pub fn trapped(&self) -> bool { + self.result.trapped + } + + /// The optional return value. Only a single return value is allowed in WebAssembly 1.0. + pub fn value(&self) -> Option { + if self.result.has_value { + assert!(!self.result.trapped); + assert!(self.value_type != sys::FizzyValueTypeVoid); + Some(match self.value_type { + sys::FizzyValueTypeI32 => TypedValue::U32(unsafe { self.result.value.i32 }), + sys::FizzyValueTypeI64 => TypedValue::U64(unsafe { self.result.value.i64 }), + sys::FizzyValueTypeF32 => TypedValue::F32(unsafe { self.result.value.f32 }), + sys::FizzyValueTypeF64 => TypedValue::F64(unsafe { self.result.value.f64 }), + _ => panic!(), + }) + } else { + None + } + } +} + impl Instance { /// Get a read-only pointer to the module. unsafe fn get_module(&self) -> *const sys::FizzyModule { @@ -275,7 +305,7 @@ impl Instance { name: &str, args: &[TypedValue], depth: i32, - ) -> Result { + ) -> Result { let func_idx = self.find_exported_function_index(&name); if func_idx.is_none() { return Err(()); @@ -304,11 +334,10 @@ impl Instance { let args: Vec = args.iter().map(|v| v.into()).collect(); let ret = unsafe { self.unsafe_execute(func_idx, &args, depth) }; - if !ret.trapped() { - // Validate presence of output whether return type is void or not. - assert!((func_type.output == sys::FizzyValueTypeVoid) == !ret.value().is_some()); - } - Ok(ret) + Ok(TypedExecutionResult { + result: ret.0, + value_type: func_type.output, + }) } } @@ -378,6 +407,86 @@ mod tests { assert_eq!(v.as_f64().unwrap(), f64::MAX); } + #[test] + fn typed_execution_result() { + let r_fail = sys::FizzyExecutionResult { + trapped: true, + has_value: false, + value: sys::FizzyValue { i32: 0 }, + }; + let r_success_void = sys::FizzyExecutionResult { + trapped: false, + has_value: false, + value: sys::FizzyValue { i32: 0 }, + }; + let r_success_u32 = sys::FizzyExecutionResult { + trapped: false, + has_value: true, + value: sys::FizzyValue { i32: u32::MAX }, + }; + let r_success_u64 = sys::FizzyExecutionResult { + trapped: false, + has_value: true, + value: sys::FizzyValue { i64: u64::MAX }, + }; + let r_success_f32 = sys::FizzyExecutionResult { + trapped: false, + has_value: true, + value: sys::FizzyValue { f32: f32::MAX }, + }; + let r_success_f64 = sys::FizzyExecutionResult { + trapped: false, + has_value: true, + value: sys::FizzyValue { f64: f64::MAX }, + }; + + let r = TypedExecutionResult { + result: r_fail, + value_type: sys::FizzyValueTypeVoid, + }; + assert!(r.trapped()); + assert!(r.value().is_none()); + + let r = TypedExecutionResult { + result: r_success_void, + value_type: sys::FizzyValueTypeVoid, + }; + assert!(!r.trapped()); + assert!(r.value().is_none()); + + let r = TypedExecutionResult { + result: r_success_u32, + value_type: sys::FizzyValueTypeI32, + }; + assert!(!r.trapped()); + assert!(r.value().is_some()); + assert_eq!(r.value().unwrap().as_u32().unwrap(), u32::MAX); + + let r = TypedExecutionResult { + result: r_success_u64, + value_type: sys::FizzyValueTypeI64, + }; + assert!(!r.trapped()); + assert!(r.value().is_some()); + assert_eq!(r.value().unwrap().as_u64().unwrap(), u64::MAX); + + let r = TypedExecutionResult { + result: r_success_f32, + value_type: sys::FizzyValueTypeF32, + }; + assert!(!r.trapped()); + assert!(r.value().is_some()); + assert_eq!(r.value().unwrap().as_f32().unwrap(), f32::MAX); + + let r = TypedExecutionResult { + result: r_success_f64, + value_type: sys::FizzyValueTypeF64, + }; + assert!(!r.trapped()); + assert!(r.value().is_some()); + assert_eq!(r.value().unwrap().as_f64().unwrap(), f64::MAX); + } + #[test] fn validate_wasm() { // Empty @@ -523,7 +632,7 @@ mod tests { let result = result.unwrap(); assert!(!result.trapped()); assert!(result.value().is_some()); - assert_eq!(result.value().unwrap().as_i32(), 42); + assert_eq!(result.value().unwrap().as_u32().unwrap(), 42); // Non-function export. let result = instance.execute("g1", &[], 0);