diff options
Diffstat (limited to 'serde_v8/magic')
-rw-r--r-- | serde_v8/magic/detached_buffer.rs | 69 | ||||
-rw-r--r-- | serde_v8/magic/mod.rs | 1 | ||||
-rw-r--r-- | serde_v8/magic/zero_copy_buf.rs | 46 |
3 files changed, 93 insertions, 23 deletions
diff --git a/serde_v8/magic/detached_buffer.rs b/serde_v8/magic/detached_buffer.rs new file mode 100644 index 000000000..1435a0fa6 --- /dev/null +++ b/serde_v8/magic/detached_buffer.rs @@ -0,0 +1,69 @@ +// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. + +use core::ops::Range; +use std::ops::Deref; +use std::ops::DerefMut; + +use super::transl8::FromV8; +use super::transl8::ToV8; +use super::zero_copy_buf::to_ranged_buffer; +use super::zero_copy_buf::ZeroCopyBuf; +use crate::magic::transl8::impl_magic; + +// A buffer that detaches when deserialized from JS +pub struct DetachedBuffer(ZeroCopyBuf); +impl_magic!(DetachedBuffer); + +impl AsRef<[u8]> for DetachedBuffer { + fn as_ref(&self) -> &[u8] { + self.0.as_ref() + } +} + +impl AsMut<[u8]> for DetachedBuffer { + fn as_mut(&mut self) -> &mut [u8] { + self.0.as_mut() + } +} + +impl Deref for DetachedBuffer { + type Target = [u8]; + fn deref(&self) -> &[u8] { + self.0.deref() + } +} + +impl DerefMut for DetachedBuffer { + fn deref_mut(&mut self) -> &mut [u8] { + self.0.deref_mut() + } +} + +impl ToV8 for DetachedBuffer { + fn to_v8<'a>( + &self, + scope: &mut v8::HandleScope<'a>, + ) -> Result<v8::Local<'a, v8::Value>, crate::Error> { + let buffer = v8::ArrayBuffer::with_backing_store(scope, &self.0.store); + let Range { start, end } = self.0.range; + let (off, len) = (start, end - start); + let v = v8::Uint8Array::new(scope, buffer, off, len).unwrap(); + Ok(v.into()) + } +} + +impl FromV8 for DetachedBuffer { + fn from_v8( + scope: &mut v8::HandleScope, + value: v8::Local<v8::Value>, + ) -> Result<Self, crate::Error> { + let (b, range) = + to_ranged_buffer(scope, value).or(Err(crate::Error::ExpectedBuffer))?; + if !b.is_detachable() { + return Err(crate::Error::ExpectedDetachable); + } + let store = b.get_backing_store(); + b.detach(); // Detach + Ok(Self(ZeroCopyBuf { store, range })) + } +} diff --git a/serde_v8/magic/mod.rs b/serde_v8/magic/mod.rs index bc86c6a7c..4f5398bda 100644 --- a/serde_v8/magic/mod.rs +++ b/serde_v8/magic/mod.rs @@ -1,6 +1,7 @@ // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. pub mod buffer; pub mod bytestring; +pub mod detached_buffer; pub mod string_or_buffer; pub mod transl8; pub mod u16string; diff --git a/serde_v8/magic/zero_copy_buf.rs b/serde_v8/magic/zero_copy_buf.rs index dcd969aea..a9dc6334c 100644 --- a/serde_v8/magic/zero_copy_buf.rs +++ b/serde_v8/magic/zero_copy_buf.rs @@ -19,8 +19,8 @@ use super::transl8::FromV8; /// `let copy = Vec::from(&*zero_copy_buf);` #[derive(Clone)] pub struct ZeroCopyBuf { - store: v8::SharedRef<v8::BackingStore>, - range: Range<usize>, + pub(crate) store: v8::SharedRef<v8::BackingStore>, + pub(crate) range: Range<usize>, } unsafe impl Send for ZeroCopyBuf {} @@ -40,17 +40,6 @@ impl ZeroCopyBuf { Ok(Self { store, range }) } - pub fn from_view( - scope: &mut v8::HandleScope, - view: v8::Local<v8::ArrayBufferView>, - ) -> Result<Self, v8::DataError> { - let buffer = view.buffer(scope).ok_or(v8::DataError::NoData { - expected: "view to have a buffer", - })?; - let (offset, len) = (view.byte_offset(), view.byte_length()); - Self::from_buffer(buffer, offset..offset + len) - } - fn as_slice(&self) -> &[u8] { unsafe { &*(&self.store[self.range.clone()] as *const _ as *const [u8]) } } @@ -61,21 +50,32 @@ impl ZeroCopyBuf { } } +pub(crate) fn to_ranged_buffer<'s>( + scope: &mut v8::HandleScope<'s>, + value: v8::Local<v8::Value>, +) -> Result<(v8::Local<'s, v8::ArrayBuffer>, Range<usize>), v8::DataError> { + if value.is_array_buffer_view() { + let view: v8::Local<v8::ArrayBufferView> = value.try_into()?; + let (offset, len) = (view.byte_offset(), view.byte_length()); + let buffer = view.buffer(scope).ok_or(v8::DataError::NoData { + expected: "view to have a buffer", + })?; + let buffer = v8::Local::new(scope, buffer); // recreate handle to avoid lifetime issues + return Ok((buffer, offset..offset + len)); + } + let b: v8::Local<v8::ArrayBuffer> = value.try_into()?; + let b = v8::Local::new(scope, b); // recreate handle to avoid lifetime issues + Ok((b, 0..b.byte_length())) +} + impl FromV8 for ZeroCopyBuf { fn from_v8( scope: &mut v8::HandleScope, value: v8::Local<v8::Value>, ) -> Result<Self, crate::Error> { - if value.is_array_buffer() { - value - .try_into() - .and_then(|b| Self::from_buffer(b, 0..b.byte_length())) - } else { - value - .try_into() - .and_then(|view| Self::from_view(scope, view)) - } - .map_err(|_| crate::Error::ExpectedBuffer) + to_ranged_buffer(scope, value) + .and_then(|(b, r)| Self::from_buffer(b, r)) + .map_err(|_| crate::Error::ExpectedBuffer) } } |