diff --git a/Cargo.lock b/Cargo.lock index 112f4bcb17..7f6f616a04 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -771,7 +771,7 @@ dependencies = [ "rusty_v8", "serde", "serde_json", - "serde_v8 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_v8", "tokio", "url", ] @@ -3336,16 +3336,6 @@ dependencies = [ "serde_json", ] -[[package]] -name = "serde_v8" -version = "0.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b431c505c5ece0caf45ffa6d089d6da7c675303aa82f8cccb76135bb1bc6a2b0" -dependencies = [ - "rusty_v8", - "serde", -] - [[package]] name = "sha-1" version = "0.9.8" diff --git a/core/Cargo.toml b/core/Cargo.toml index 3d2c7d3353..c39dbf1854 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -24,7 +24,7 @@ pin-project = "1.0.7" rusty_v8 = "0.32.0" serde = { version = "1.0.129", features = ["derive"] } serde_json = { version = "1.0.66", features = ["preserve_order"] } -serde_v8 = "0.15.0" +serde_v8 = { version = "0.15.0", path = "../serde_v8" } url = { version = "2.2.2", features = ["serde"] } [[example]] diff --git a/core/lib.rs b/core/lib.rs index c0419f8abd..889f613dfa 100644 --- a/core/lib.rs +++ b/core/lib.rs @@ -26,6 +26,7 @@ pub use serde_json; pub use serde_v8; pub use serde_v8::Buffer as ZeroCopyBuf; pub use serde_v8::ByteString; +pub use serde_v8::StringOrBuffer; pub use url; pub use crate::async_cancel::CancelFuture; diff --git a/serde_v8/src/de.rs b/serde_v8/src/de.rs index 3668a4fd58..d4338a37fe 100644 --- a/serde_v8/src/de.rs +++ b/serde_v8/src/de.rs @@ -132,6 +132,16 @@ impl<'de, 'a, 'b, 's, 'x> de::Deserializer<'de> ValueType::String => self.deserialize_string(visitor), ValueType::Array => self.deserialize_seq(visitor), ValueType::Object => self.deserialize_map(visitor), + // Map to Vec when deserialized via deserialize_any + // e.g: for untagged enums or StringOrBuffer + ValueType::ArrayBufferView => { + v8::Local::::try_from(self.input) + .and_then(|view| { + magic::zero_copy_buf::ZeroCopyBuf::try_new(self.scope, view) + }) + .map_err(|_| Error::ExpectedInteger) + .and_then(|zb| visitor.visit_byte_buf(Vec::from(&*zb))) + } } } diff --git a/serde_v8/src/lib.rs b/serde_v8/src/lib.rs index 374a27ce26..d97b1f1afe 100644 --- a/serde_v8/src/lib.rs +++ b/serde_v8/src/lib.rs @@ -13,6 +13,7 @@ pub use error::{Error, Result}; pub use keys::KeyCache; pub use magic::buffer::MagicBuffer as Buffer; pub use magic::bytestring::ByteString; +pub use magic::string_or_buffer::StringOrBuffer; pub use magic::Value; pub use ser::{to_v8, Serializer}; pub use serializable::{Serializable, SerializablePkg}; diff --git a/serde_v8/src/magic/mod.rs b/serde_v8/src/magic/mod.rs index 00c06fd4ce..91a09e2f4b 100644 --- a/serde_v8/src/magic/mod.rs +++ b/serde_v8/src/magic/mod.rs @@ -2,6 +2,7 @@ pub mod buffer; pub mod bytestring; mod field; +pub mod string_or_buffer; mod value; pub mod zero_copy_buf; diff --git a/serde_v8/src/magic/string_or_buffer.rs b/serde_v8/src/magic/string_or_buffer.rs new file mode 100644 index 0000000000..88a6344c40 --- /dev/null +++ b/serde_v8/src/magic/string_or_buffer.rs @@ -0,0 +1,38 @@ +use std::ops::Deref; + +#[derive(Debug)] +pub struct StringOrBuffer(Vec); + +impl Deref for StringOrBuffer { + type Target = Vec; + fn deref(&self) -> &Vec { + &self.0 + } +} + +impl<'de> serde::Deserialize<'de> for StringOrBuffer { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + StringOrBufferInner::deserialize(deserializer) + .map(|x| StringOrBuffer(x.into_bytes())) + } +} + +// TODO(@AaronO): explore if we can make this work with ZeroCopyBuf +#[derive(serde::Deserialize)] +#[serde(untagged)] +enum StringOrBufferInner { + String(String), + Buffer(Vec), +} + +impl StringOrBufferInner { + fn into_bytes(self) -> Vec { + match self { + Self::String(s) => s.into_bytes(), + Self::Buffer(b) => b, + } + } +} diff --git a/serde_v8/src/payload.rs b/serde_v8/src/payload.rs index 816158f93c..a9fb045e37 100644 --- a/serde_v8/src/payload.rs +++ b/serde_v8/src/payload.rs @@ -5,12 +5,14 @@ use rusty_v8 as v8; // so it can implement Deserialize by itself // Classifies v8::Values into sub-types +#[derive(Debug)] pub enum ValueType { Null, Bool, Number, String, Array, + ArrayBufferView, Object, } @@ -24,6 +26,8 @@ impl ValueType { return Self::String; } else if v.is_array() { return Self::Array; + } else if v.is_array_buffer_view() { + return Self::ArrayBufferView; } else if v.is_object() { return Self::Object; } else if v.is_null_or_undefined() { diff --git a/serde_v8/tests/de.rs b/serde_v8/tests/de.rs index e036fd6839..888bff4f49 100644 --- a/serde_v8/tests/de.rs +++ b/serde_v8/tests/de.rs @@ -168,6 +168,22 @@ fn de_map() { }) } +#[test] +fn de_string_or_buffer() { + dedo("'hello'", |scope, v| { + let sob: serde_v8::StringOrBuffer = serde_v8::from_v8(scope, v).unwrap(); + assert_eq!(sob.as_slice(), &[0x68, 0x65, 0x6C, 0x6C, 0x6F]); + }); + + dedo( + "(Uint8Array.from([0x68, 0x65, 0x6C, 0x6C, 0x6F]))", + |scope, v| { + let sob: serde_v8::StringOrBuffer = serde_v8::from_v8(scope, v).unwrap(); + assert_eq!(sob.as_slice(), &[0x68, 0x65, 0x6C, 0x6C, 0x6F]); + }, + ); +} + //// // JSON tests: serde_json::Value compatibility ////