diff --git a/wasm-rpc/Cargo.toml b/wasm-rpc/Cargo.toml index 9e167fb7..11c690db 100644 --- a/wasm-rpc/Cargo.toml +++ b/wasm-rpc/Cargo.toml @@ -33,10 +33,12 @@ prost-build = "0.12.3" [features] default = ["host"] -host = ["arbitrary", "json", "protobuf", "typeinfo", "wasmtime"] +host = ["arbitrary", "bincode", "json", "protobuf", "serde", "typeinfo", "wasmtime"] arbitrary = ["dep:arbitrary"] +bincode = ["dep:bincode"] json = ["dep:serde", "dep:serde_json", "dep:bigdecimal", "typeinfo"] protobuf = ["dep:bincode", "dep:serde", "dep:prost"] +serde = ["dep:serde"] stub = [] typeinfo = ["dep:golem-wasm-ast"] wasmtime = ["dep:wasmtime", "typeinfo"] diff --git a/wasm-rpc/src/bincode.rs b/wasm-rpc/src/bincode.rs new file mode 100644 index 00000000..d5b74804 --- /dev/null +++ b/wasm-rpc/src/bincode.rs @@ -0,0 +1,353 @@ +use crate::{Uri, WitNode, WitValue}; +use bincode::de::{BorrowDecoder, Decoder}; +use bincode::enc::Encoder; +use bincode::error::{AllowedEnumVariants, DecodeError, EncodeError}; +use bincode::*; + +impl Encode for WitValue { + fn encode(&self, encoder: &mut E) -> Result<(), EncodeError> { + self.nodes.encode(encoder) + } +} + +impl Decode for WitValue { + fn decode(decoder: &mut D) -> Result { + let nodes = Vec::::decode(decoder)?; + Ok(WitValue { nodes }) + } +} + +impl<'de> BorrowDecode<'de> for WitValue { + fn borrow_decode>(decoder: &mut D) -> Result { + let nodes = Vec::::borrow_decode(decoder)?; + Ok(WitValue { nodes }) + } +} + +impl Encode for WitNode { + fn encode(&self, encoder: &mut E) -> Result<(), EncodeError> { + match self { + WitNode::RecordValue(field_indices) => { + 0u8.encode(encoder)?; + field_indices.encode(encoder) + } + WitNode::VariantValue((cons_idx, value_idx)) => { + 1u8.encode(encoder)?; + cons_idx.encode(encoder)?; + value_idx.encode(encoder) + } + WitNode::EnumValue(value) => { + 2u8.encode(encoder)?; + value.encode(encoder) + } + WitNode::FlagsValue(values) => { + 3u8.encode(encoder)?; + values.encode(encoder) + } + WitNode::TupleValue(value_indices) => { + 4u8.encode(encoder)?; + value_indices.encode(encoder) + } + WitNode::ListValue(value_indices) => { + 5u8.encode(encoder)?; + value_indices.encode(encoder) + } + WitNode::OptionValue(opt_idx) => { + 6u8.encode(encoder)?; + opt_idx.encode(encoder) + } + WitNode::ResultValue(res_idx) => { + 7u8.encode(encoder)?; + res_idx.encode(encoder) + } + WitNode::PrimU8(value) => { + 8u8.encode(encoder)?; + value.encode(encoder) + } + WitNode::PrimU16(value) => { + 9u8.encode(encoder)?; + value.encode(encoder) + } + WitNode::PrimU32(value) => { + 10u8.encode(encoder)?; + value.encode(encoder) + } + WitNode::PrimU64(value) => { + 11u8.encode(encoder)?; + value.encode(encoder) + } + WitNode::PrimS8(value) => { + 12u8.encode(encoder)?; + value.encode(encoder) + } + WitNode::PrimS16(value) => { + 13u8.encode(encoder)?; + value.encode(encoder) + } + WitNode::PrimS32(value) => { + 14u8.encode(encoder)?; + value.encode(encoder) + } + WitNode::PrimS64(value) => { + 15u8.encode(encoder)?; + value.encode(encoder) + } + WitNode::PrimFloat32(value) => { + 16u8.encode(encoder)?; + value.encode(encoder) + } + WitNode::PrimFloat64(value) => { + 17u8.encode(encoder)?; + value.encode(encoder) + } + WitNode::PrimChar(value) => { + 18u8.encode(encoder)?; + value.encode(encoder) + } + WitNode::PrimBool(value) => { + 19u8.encode(encoder)?; + value.encode(encoder) + } + WitNode::PrimString(value) => { + 20u8.encode(encoder)?; + value.encode(encoder) + } + WitNode::Handle((uri, value)) => { + 21u8.encode(encoder)?; + uri.value.encode(encoder)?; + value.encode(encoder) + } + } + } +} + +impl Decode for WitNode { + fn decode(decoder: &mut D) -> Result { + let tag: u8 = Decode::decode(decoder)?; + match tag { + 0u8 => { + let field_indices = Vec::::decode(decoder)?; + Ok(WitNode::RecordValue(field_indices)) + } + 1u8 => { + let cons_idx = u32::decode(decoder)?; + let value_idx = Option::::decode(decoder)?; + Ok(WitNode::VariantValue((cons_idx, value_idx))) + } + 2u8 => { + let value = u32::decode(decoder)?; + Ok(WitNode::EnumValue(value)) + } + 3u8 => { + let values = Vec::::decode(decoder)?; + Ok(WitNode::FlagsValue(values)) + } + 4u8 => { + let value_indices = Vec::::decode(decoder)?; + Ok(WitNode::TupleValue(value_indices)) + } + 5u8 => { + let value_indices = Vec::::decode(decoder)?; + Ok(WitNode::ListValue(value_indices)) + } + 6u8 => { + let opt_idx = Option::::decode(decoder)?; + Ok(WitNode::OptionValue(opt_idx)) + } + 7u8 => { + let res_idx = Result::, Option>::decode(decoder)?; + Ok(WitNode::ResultValue(res_idx)) + } + 8u8 => { + let value = u8::decode(decoder)?; + Ok(WitNode::PrimU8(value)) + } + 9u8 => { + let value = u16::decode(decoder)?; + Ok(WitNode::PrimU16(value)) + } + 10u8 => { + let value = u32::decode(decoder)?; + Ok(WitNode::PrimU32(value)) + } + 11u8 => { + let value = u64::decode(decoder)?; + Ok(WitNode::PrimU64(value)) + } + 12u8 => { + let value = i8::decode(decoder)?; + Ok(WitNode::PrimS8(value)) + } + 13u8 => { + let value = i16::decode(decoder)?; + Ok(WitNode::PrimS16(value)) + } + 14u8 => { + let value = i32::decode(decoder)?; + Ok(WitNode::PrimS32(value)) + } + 15u8 => { + let value = i64::decode(decoder)?; + Ok(WitNode::PrimS64(value)) + } + 16u8 => { + let value = f32::decode(decoder)?; + Ok(WitNode::PrimFloat32(value)) + } + 17u8 => { + let value = f64::decode(decoder)?; + Ok(WitNode::PrimFloat64(value)) + } + 18u8 => { + let value = char::decode(decoder)?; + Ok(WitNode::PrimChar(value)) + } + 19u8 => { + let value = bool::decode(decoder)?; + Ok(WitNode::PrimBool(value)) + } + 20u8 => { + let value = String::decode(decoder)?; + Ok(WitNode::PrimString(value)) + } + 21u8 => { + let uri = String::decode(decoder)?; + let value = u64::decode(decoder)?; + Ok(WitNode::Handle((Uri { value: uri }, value))) + } + _ => Err(DecodeError::UnexpectedVariant { + found: tag as u32, + type_name: "WitNode", + allowed: &AllowedEnumVariants::Range { min: 0, max: 21 }, + }), + } + } +} + +impl<'de> BorrowDecode<'de> for WitNode { + fn borrow_decode>(decoder: &mut D) -> Result { + let tag: u8 = BorrowDecode::borrow_decode(decoder)?; + match tag { + 0u8 => { + let field_indices = Vec::::borrow_decode(decoder)?; + Ok(WitNode::RecordValue(field_indices)) + } + 1u8 => { + let cons_idx = u32::borrow_decode(decoder)?; + let value_idx = Option::::borrow_decode(decoder)?; + Ok(WitNode::VariantValue((cons_idx, value_idx))) + } + 2u8 => { + let value = u32::borrow_decode(decoder)?; + Ok(WitNode::EnumValue(value)) + } + 3u8 => { + let values = Vec::::borrow_decode(decoder)?; + Ok(WitNode::FlagsValue(values)) + } + 4u8 => { + let value_indices = Vec::::borrow_decode(decoder)?; + Ok(WitNode::TupleValue(value_indices)) + } + 5u8 => { + let value_indices = Vec::::borrow_decode(decoder)?; + Ok(WitNode::ListValue(value_indices)) + } + 6u8 => { + let opt_idx = Option::::borrow_decode(decoder)?; + Ok(WitNode::OptionValue(opt_idx)) + } + 7u8 => { + let res_idx = Result::, Option>::borrow_decode(decoder)?; + Ok(WitNode::ResultValue(res_idx)) + } + 8u8 => { + let value = u8::borrow_decode(decoder)?; + Ok(WitNode::PrimU8(value)) + } + 9u8 => { + let value = u16::borrow_decode(decoder)?; + Ok(WitNode::PrimU16(value)) + } + 10u8 => { + let value = u32::borrow_decode(decoder)?; + Ok(WitNode::PrimU32(value)) + } + 11u8 => { + let value = u64::borrow_decode(decoder)?; + Ok(WitNode::PrimU64(value)) + } + 12u8 => { + let value = i8::borrow_decode(decoder)?; + Ok(WitNode::PrimS8(value)) + } + 13u8 => { + let value = i16::borrow_decode(decoder)?; + Ok(WitNode::PrimS16(value)) + } + 14u8 => { + let value = i32::borrow_decode(decoder)?; + Ok(WitNode::PrimS32(value)) + } + 15u8 => { + let value = i64::borrow_decode(decoder)?; + Ok(WitNode::PrimS64(value)) + } + 16u8 => { + let value = f32::borrow_decode(decoder)?; + Ok(WitNode::PrimFloat32(value)) + } + 17u8 => { + let value = f64::borrow_decode(decoder)?; + Ok(WitNode::PrimFloat64(value)) + } + 18u8 => { + let value = char::borrow_decode(decoder)?; + Ok(WitNode::PrimChar(value)) + } + 19u8 => { + let value = bool::borrow_decode(decoder)?; + Ok(WitNode::PrimBool(value)) + } + 20u8 => { + let value = String::borrow_decode(decoder)?; + Ok(WitNode::PrimString(value)) + } + 21u8 => { + let uri = String::borrow_decode(decoder)?; + let value = u64::borrow_decode(decoder)?; + Ok(WitNode::Handle((Uri { value: uri }, value))) + } + _ => Err(DecodeError::UnexpectedVariant { + found: tag as u32, + type_name: "WitNode", + allowed: &AllowedEnumVariants::Range { min: 0, max: 21 }, + }), + } + } +} + +#[cfg(test)] +mod tests { + use crate::{Value, WitValue}; + use proptest::prelude::*; + use proptest_arbitrary_interop::arb_sized; + + const CASES: u32 = 10000; + const SIZE: usize = 4096; + + proptest! { + + #![proptest_config(ProptestConfig { + cases: CASES, .. ProptestConfig::default() + })] + #[test] + fn round_trip(value in arb_sized::(SIZE).prop_filter("Value must be equal to itself", |v| v.eq(v))) { + let wit_value: WitValue = value.clone().into(); + let encoded = bincode::encode_to_vec(wit_value, bincode::config::standard()).unwrap(); + let (decoded, _): (WitValue, usize) = bincode::decode_from_slice(&encoded, bincode::config::standard()).unwrap(); + let round_trip_value: Value = decoded.into(); + prop_assert_eq!(value, round_trip_value); + } + } +} diff --git a/wasm-rpc/src/lib.rs b/wasm-rpc/src/lib.rs index 8e3bd9b2..058917a1 100644 --- a/wasm-rpc/src/lib.rs +++ b/wasm-rpc/src/lib.rs @@ -18,6 +18,9 @@ #[cfg(feature = "stub")] mod bindings; +/// Implements bincode encoders and decoders for WitValue instances +#[cfg(feature = "bincode")] +pub mod bincode; /// A builder interface for WitValue instances mod builder; @@ -32,6 +35,10 @@ pub mod json; #[cfg(feature = "protobuf")] pub mod protobuf; +/// Serde instances for WitValue +#[cfg(feature = "serde")] +pub mod serde; + #[cfg(feature = "wasmtime")] pub mod wasmtime; diff --git a/wasm-rpc/src/serde.rs b/wasm-rpc/src/serde.rs new file mode 100644 index 00000000..77a818a3 --- /dev/null +++ b/wasm-rpc/src/serde.rs @@ -0,0 +1,25 @@ +use crate::WitValue; +use serde::{Deserialize, Deserializer, Serialize}; + +impl<'de> Deserialize<'de> for WitValue { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let binary = Vec::::deserialize(deserializer)?; + bincode::decode_from_slice(&binary, bincode::config::standard()) + .map_err(serde::de::Error::custom) + .map(|(value, _)| value) + } +} + +impl Serialize for WitValue { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let binary = bincode::encode_to_vec(self, bincode::config::standard()) + .map_err(serde::ser::Error::custom)?; + binary.serialize(serializer) + } +}