diff options
-rw-r--r-- | serde_v8/src/de.rs | 33 | ||||
-rw-r--r-- | serde_v8/src/error.rs | 1 | ||||
-rw-r--r-- | serde_v8/src/magic/buffer.rs | 32 | ||||
-rw-r--r-- | serde_v8/src/magic/zero_copy_buf.rs | 57 | ||||
-rw-r--r-- | serde_v8/src/payload.rs | 3 | ||||
-rw-r--r-- | serde_v8/tests/de.rs | 24 |
6 files changed, 110 insertions, 40 deletions
diff --git a/serde_v8/src/de.rs b/serde_v8/src/de.rs index 69e618cb3..2deb5da39 100644 --- a/serde_v8/src/de.rs +++ b/serde_v8/src/de.rs @@ -134,9 +134,20 @@ impl<'de, 'a, 'b, 's, 'x> de::Deserializer<'de> ValueType::ArrayBufferView => { v8::Local::<v8::ArrayBufferView>::try_from(self.input) .and_then(|view| { - magic::zero_copy_buf::ZeroCopyBuf::try_new(self.scope, view) + magic::zero_copy_buf::ZeroCopyBuf::try_from(( + &mut *self.scope, + view, + )) }) - .map_err(|_| Error::ExpectedInteger) + .map_err(|_| Error::ExpectedBuffer) + .and_then(|zb| visitor.visit_byte_buf(Vec::from(&*zb))) + } + ValueType::ArrayBuffer => { + v8::Local::<v8::ArrayBuffer>::try_from(self.input) + .and_then(|buffer| { + magic::zero_copy_buf::ZeroCopyBuf::try_from(buffer) + }) + .map_err(|_| Error::ExpectedBuffer) .and_then(|zb| visitor.visit_byte_buf(Vec::from(&*zb))) } } @@ -339,12 +350,20 @@ impl<'de, 'a, 'b, 's, 'x> de::Deserializer<'de> // Magic Buffer if name == magic::buffer::BUF_NAME { - let zero_copy_buf = - v8::Local::<v8::ArrayBufferView>::try_from(self.input) + let zero_copy_buf = match self.input.is_array_buffer() { + // ArrayBuffer + true => v8::Local::<v8::ArrayBuffer>::try_from(self.input) + .and_then(magic::zero_copy_buf::ZeroCopyBuf::try_from), + // maybe ArrayBufferView + false => v8::Local::<v8::ArrayBufferView>::try_from(self.input) .and_then(|view| { - magic::zero_copy_buf::ZeroCopyBuf::try_new(self.scope, view) - }) - .map_err(|_| Error::ExpectedArray)?; + magic::zero_copy_buf::ZeroCopyBuf::try_from(( + &mut *self.scope, + view, + )) + }), + } + .map_err(|_| Error::ExpectedBuffer)?; let data: [u8; 32] = unsafe { std::mem::transmute(zero_copy_buf) }; return visitor.visit_bytes(&data); } diff --git a/serde_v8/src/error.rs b/serde_v8/src/error.rs index 523dd62b0..6f4305536 100644 --- a/serde_v8/src/error.rs +++ b/serde_v8/src/error.rs @@ -16,6 +16,7 @@ pub enum Error { ExpectedMap, ExpectedEnum, ExpectedObject, + ExpectedBuffer, ExpectedUtf8, diff --git a/serde_v8/src/magic/buffer.rs b/serde_v8/src/magic/buffer.rs index 80f2f8bc7..e6f85324e 100644 --- a/serde_v8/src/magic/buffer.rs +++ b/serde_v8/src/magic/buffer.rs @@ -1,5 +1,6 @@ // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. +use std::convert::TryFrom; use std::fmt; use std::ops::Deref; use std::ops::DerefMut; @@ -15,22 +16,29 @@ pub enum MagicBuffer { } impl MagicBuffer { - pub fn new<'s>( - scope: &mut v8::HandleScope<'s>, - view: v8::Local<v8::ArrayBufferView>, - ) -> Self { - Self::try_new(scope, view).unwrap() + pub fn empty() -> Self { + MagicBuffer::ToV8(Mutex::new(Some(vec![0_u8; 0].into_boxed_slice()))) } +} - pub fn try_new<'s>( - scope: &mut v8::HandleScope<'s>, - view: v8::Local<v8::ArrayBufferView>, - ) -> Result<Self, v8::DataError> { - Ok(Self::FromV8(ZeroCopyBuf::try_new(scope, view)?)) +impl<'s> TryFrom<v8::Local<'s, v8::ArrayBuffer>> for MagicBuffer { + type Error = v8::DataError; + fn try_from(buffer: v8::Local<v8::ArrayBuffer>) -> Result<Self, Self::Error> { + Ok(Self::FromV8(ZeroCopyBuf::try_from(buffer)?)) } +} - pub fn empty() -> Self { - MagicBuffer::ToV8(Mutex::new(Some(vec![0_u8; 0].into_boxed_slice()))) +// TODO(@AaronO): consider streamlining this as "ScopedValue" ? +type ScopedView<'a, 'b, 's> = ( + &'s mut v8::HandleScope<'a>, + v8::Local<'b, v8::ArrayBufferView>, +); +impl<'a, 'b, 's> TryFrom<ScopedView<'a, 'b, 's>> for MagicBuffer { + type Error = v8::DataError; + fn try_from( + scoped_view: ScopedView<'a, 'b, 's>, + ) -> Result<Self, Self::Error> { + Ok(Self::FromV8(ZeroCopyBuf::try_from(scoped_view)?)) } } diff --git a/serde_v8/src/magic/zero_copy_buf.rs b/serde_v8/src/magic/zero_copy_buf.rs index b536f5859..30acd8137 100644 --- a/serde_v8/src/magic/zero_copy_buf.rs +++ b/serde_v8/src/magic/zero_copy_buf.rs @@ -25,31 +25,46 @@ pub struct ZeroCopyBuf { unsafe impl Send for ZeroCopyBuf {} impl ZeroCopyBuf { - pub fn new<'s>( - scope: &mut v8::HandleScope<'s>, - view: v8::Local<v8::ArrayBufferView>, - ) -> Self { - Self::try_new(scope, view).unwrap() - } - - pub fn try_new<'s>( - scope: &mut v8::HandleScope<'s>, - view: v8::Local<v8::ArrayBufferView>, + pub fn from_buffer( + buffer: v8::Local<v8::ArrayBuffer>, + byte_offset: usize, + byte_length: usize, ) -> Result<Self, v8::DataError> { - let backing_store = view.buffer(scope).unwrap().get_backing_store(); - if backing_store.is_shared() { - return Err(v8::DataError::BadType { + let backing_store = buffer.get_backing_store(); + match backing_store.is_shared() { + true => Err(v8::DataError::BadType { actual: "shared ArrayBufferView", expected: "non-shared ArrayBufferView", - }); + }), + false => Ok(Self { + backing_store, + byte_offset, + byte_length, + }), } - let byte_offset = view.byte_offset(); - let byte_length = view.byte_length(); - Ok(Self { - backing_store, - byte_offset, - byte_length, - }) + } +} + +impl<'s> TryFrom<v8::Local<'s, v8::ArrayBuffer>> for ZeroCopyBuf { + type Error = v8::DataError; + fn try_from(buffer: v8::Local<v8::ArrayBuffer>) -> Result<Self, Self::Error> { + Self::from_buffer(buffer, 0, buffer.byte_length()) + } +} + +// TODO(@AaronO): consider streamlining this as "ScopedValue" ? +type ScopedView<'a, 'b, 's> = ( + &'s mut v8::HandleScope<'a>, + v8::Local<'b, v8::ArrayBufferView>, +); +impl<'a, 'b, 's> TryFrom<ScopedView<'a, 'b, 's>> for ZeroCopyBuf { + type Error = v8::DataError; + fn try_from( + scoped_view: ScopedView<'a, 'b, 's>, + ) -> Result<Self, Self::Error> { + let (scope, view) = scoped_view; + let buffer = view.buffer(scope).unwrap(); + Self::from_buffer(buffer, view.byte_offset(), view.byte_length()) } } diff --git a/serde_v8/src/payload.rs b/serde_v8/src/payload.rs index 145066403..c9f3e85aa 100644 --- a/serde_v8/src/payload.rs +++ b/serde_v8/src/payload.rs @@ -11,6 +11,7 @@ pub enum ValueType { Number, String, Array, + ArrayBuffer, ArrayBufferView, Object, } @@ -25,6 +26,8 @@ impl ValueType { return Self::String; } else if v.is_array() { return Self::Array; + } else if v.is_array_buffer() { + return Self::ArrayBuffer; } else if v.is_array_buffer_view() { return Self::ArrayBufferView; } else if v.is_object() { diff --git a/serde_v8/tests/de.rs b/serde_v8/tests/de.rs index 2b85d8839..1253ea92b 100644 --- a/serde_v8/tests/de.rs +++ b/serde_v8/tests/de.rs @@ -2,6 +2,7 @@ use serde::Deserialize; use serde_v8::utils::{js_exec, v8_do}; +use serde_v8::Buffer; use serde_v8::Error; #[derive(Debug, Deserialize, PartialEq)] @@ -192,6 +193,29 @@ fn de_string_or_buffer() { ); } +#[test] +fn de_buffers() { + // ArrayBufferView + dedo("new Uint8Array([97])", |scope, v| { + let buf: Buffer = serde_v8::from_v8(scope, v).unwrap(); + assert_eq!(&*buf, &[97]); + }); + + // ArrayBuffer + dedo("(new Uint8Array([97])).buffer", |scope, v| { + let buf: Buffer = serde_v8::from_v8(scope, v).unwrap(); + assert_eq!(&*buf, &[97]); + }); + + dedo( + "(Uint8Array.from([0x68, 0x65, 0x6C, 0x6C, 0x6F]))", + |scope, v| { + let buf: Buffer = serde_v8::from_v8(scope, v).unwrap(); + assert_eq!(&*buf, &[0x68, 0x65, 0x6C, 0x6C, 0x6F]); + }, + ); +} + //// // JSON tests: serde_json::Value compatibility //// |