diff options
Diffstat (limited to 'serde_v8/magic')
-rw-r--r-- | serde_v8/magic/any_value.rs | 68 | ||||
-rw-r--r-- | serde_v8/magic/bigint.rs | 77 | ||||
-rw-r--r-- | serde_v8/magic/buffer.rs | 119 | ||||
-rw-r--r-- | serde_v8/magic/bytestring.rs | 109 | ||||
-rw-r--r-- | serde_v8/magic/detached_buffer.rs | 70 | ||||
-rw-r--r-- | serde_v8/magic/external_pointer.rs | 58 | ||||
-rw-r--r-- | serde_v8/magic/global.rs | 41 | ||||
-rw-r--r-- | serde_v8/magic/mod.rs | 17 | ||||
-rw-r--r-- | serde_v8/magic/rawbytes.rs | 122 | ||||
-rw-r--r-- | serde_v8/magic/string_or_buffer.rs | 58 | ||||
-rw-r--r-- | serde_v8/magic/transl8.rs | 165 | ||||
-rw-r--r-- | serde_v8/magic/u16string.rs | 59 | ||||
-rw-r--r-- | serde_v8/magic/v8slice.rs | 181 | ||||
-rw-r--r-- | serde_v8/magic/value.rs | 48 |
14 files changed, 0 insertions, 1192 deletions
diff --git a/serde_v8/magic/any_value.rs b/serde_v8/magic/any_value.rs deleted file mode 100644 index df85f90d8..000000000 --- a/serde_v8/magic/any_value.rs +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. -use super::buffer::JsBuffer; -use super::transl8::FromV8; -use super::transl8::ToV8; -use crate::magic::transl8::impl_magic; -use crate::Error; -use crate::ToJsBuffer; -use num_bigint::BigInt; - -/// An untagged enum type that can be any of number, string, bool, bigint, or -/// buffer. -#[derive(Debug)] -pub enum AnyValue { - RustBuffer(ToJsBuffer), - V8Buffer(JsBuffer), - String(String), - Number(f64), - BigInt(BigInt), - Bool(bool), -} - -impl_magic!(AnyValue); - -impl ToV8 for AnyValue { - fn to_v8<'a>( - &mut self, - scope: &mut v8::HandleScope<'a>, - ) -> Result<v8::Local<'a, v8::Value>, crate::Error> { - match self { - Self::RustBuffer(buf) => crate::to_v8(scope, buf), - Self::V8Buffer(_) => unreachable!(), - Self::String(s) => crate::to_v8(scope, s), - Self::Number(num) => crate::to_v8(scope, num), - Self::BigInt(bigint) => { - crate::to_v8(scope, crate::BigInt::from(bigint.clone())) - } - Self::Bool(b) => crate::to_v8(scope, b), - } - } -} - -impl FromV8 for AnyValue { - fn from_v8( - scope: &mut v8::HandleScope, - value: v8::Local<v8::Value>, - ) -> Result<Self, crate::Error> { - if value.is_string() { - let string = crate::from_v8(scope, value)?; - Ok(AnyValue::String(string)) - } else if value.is_number() { - let string = crate::from_v8(scope, value)?; - Ok(AnyValue::Number(string)) - } else if value.is_big_int() { - let bigint = crate::BigInt::from_v8(scope, value)?; - Ok(AnyValue::BigInt(bigint.into())) - } else if value.is_array_buffer_view() { - let buf = JsBuffer::from_v8(scope, value)?; - Ok(AnyValue::V8Buffer(buf)) - } else if value.is_boolean() { - let string = crate::from_v8(scope, value)?; - Ok(AnyValue::Bool(string)) - } else { - Err(Error::Message( - "expected string, number, bigint, ArrayBufferView, boolean".into(), - )) - } - } -} diff --git a/serde_v8/magic/bigint.rs b/serde_v8/magic/bigint.rs deleted file mode 100644 index 330803daf..000000000 --- a/serde_v8/magic/bigint.rs +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. - -use smallvec::smallvec; -use smallvec::SmallVec; - -use super::transl8::FromV8; -use super::transl8::ToV8; -use crate::error::value_to_type_str; -use crate::magic::transl8::impl_magic; -use crate::Error; - -#[derive( - PartialEq, - Eq, - Clone, - Debug, - Default, - derive_more::Deref, - derive_more::DerefMut, - derive_more::AsRef, - derive_more::AsMut, -)] -#[as_mut(forward)] -#[as_ref(forward)] -pub struct BigInt(num_bigint::BigInt); -impl_magic!(BigInt); - -impl ToV8 for BigInt { - fn to_v8<'a>( - &mut self, - scope: &mut v8::HandleScope<'a>, - ) -> Result<v8::Local<'a, v8::Value>, crate::Error> { - let (sign, words) = self.0.to_u64_digits(); - let sign_bit = sign == num_bigint::Sign::Minus; - let v = v8::BigInt::new_from_words(scope, sign_bit, &words).unwrap(); - Ok(v.into()) - } -} - -impl FromV8 for BigInt { - fn from_v8( - _scope: &mut v8::HandleScope, - value: v8::Local<v8::Value>, - ) -> Result<Self, crate::Error> { - let v8bigint = v8::Local::<v8::BigInt>::try_from(value) - .map_err(|_| Error::ExpectedBigInt(value_to_type_str(value)))?; - let word_count = v8bigint.word_count(); - let mut words: SmallVec<[u64; 1]> = smallvec![0u64; word_count]; - let (sign_bit, _words) = v8bigint.to_words_array(&mut words); - let sign = match sign_bit { - true => num_bigint::Sign::Minus, - false => num_bigint::Sign::Plus, - }; - // SAFETY: Because the alignment of u64 is 8, the alignment of u32 is 4, and - // the size of u64 is 8, the size of u32 is 4, the alignment of u32 is a - // factor of the alignment of u64, and the size of u32 is a factor of the - // size of u64, we can safely transmute the slice of u64 to a slice of u32. - let (prefix, slice, suffix) = unsafe { words.align_to::<u32>() }; - assert!(prefix.is_empty()); - assert!(suffix.is_empty()); - assert_eq!(slice.len(), words.len() * 2); - let big_int = num_bigint::BigInt::from_slice(sign, slice); - Ok(Self(big_int)) - } -} - -impl From<num_bigint::BigInt> for BigInt { - fn from(big_int: num_bigint::BigInt) -> Self { - Self(big_int) - } -} - -impl From<BigInt> for num_bigint::BigInt { - fn from(big_int: BigInt) -> Self { - big_int.0 - } -} diff --git a/serde_v8/magic/buffer.rs b/serde_v8/magic/buffer.rs deleted file mode 100644 index 032a3be33..000000000 --- a/serde_v8/magic/buffer.rs +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. - -use std::fmt::Debug; -use std::ops::Deref; -use std::ops::DerefMut; - -use super::transl8::FromV8; -use super::transl8::ToV8; -use super::v8slice::V8Slice; -use crate::magic::transl8::impl_magic; - -pub struct JsBuffer(V8Slice); - -impl_magic!(JsBuffer); - -impl Debug for JsBuffer { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_list().entries(self.0.as_ref().iter()).finish() - } -} - -impl Clone for JsBuffer { - fn clone(&self) -> Self { - Self(self.0.clone()) - } -} - -impl AsRef<[u8]> for JsBuffer { - fn as_ref(&self) -> &[u8] { - &self.0 - } -} - -impl AsMut<[u8]> for JsBuffer { - fn as_mut(&mut self) -> &mut [u8] { - &mut self.0 - } -} - -impl Deref for JsBuffer { - type Target = [u8]; - fn deref(&self) -> &[u8] { - &self.0 - } -} - -impl DerefMut for JsBuffer { - fn deref_mut(&mut self) -> &mut [u8] { - &mut self.0 - } -} - -impl FromV8 for JsBuffer { - fn from_v8( - scope: &mut v8::HandleScope, - value: v8::Local<v8::Value>, - ) -> Result<Self, crate::Error> { - Ok(Self(V8Slice::from_v8(scope, value)?)) - } -} - -impl From<JsBuffer> for bytes::Bytes { - fn from(zbuf: JsBuffer) -> bytes::Bytes { - zbuf.0.into() - } -} - -// NOTE(bartlomieju): we use Option here, because `to_v8()` uses `&mut self` -// instead of `self` which is dictated by the `serde` API. -#[derive(Debug)] -pub struct ToJsBuffer(Option<Box<[u8]>>); - -impl_magic!(ToJsBuffer); - -impl ToJsBuffer { - pub fn empty() -> Self { - ToJsBuffer(Some(vec![0_u8; 0].into_boxed_slice())) - } -} - -impl From<Box<[u8]>> for ToJsBuffer { - fn from(buf: Box<[u8]>) -> Self { - ToJsBuffer(Some(buf)) - } -} - -impl From<Vec<u8>> for ToJsBuffer { - fn from(vec: Vec<u8>) -> Self { - vec.into_boxed_slice().into() - } -} - -impl ToV8 for ToJsBuffer { - fn to_v8<'a>( - &mut self, - scope: &mut v8::HandleScope<'a>, - ) -> Result<v8::Local<'a, v8::Value>, crate::Error> { - let buf: Box<[u8]> = self.0.take().expect("RustToV8Buf was empty"); - - if buf.is_empty() { - let ab = v8::ArrayBuffer::new(scope, 0); - return Ok( - v8::Uint8Array::new(scope, ab, 0, 0) - .expect("Failed to create Uint8Array") - .into(), - ); - } - let buf_len: usize = buf.len(); - let backing_store = - v8::ArrayBuffer::new_backing_store_from_boxed_slice(buf); - let backing_store_shared = backing_store.make_shared(); - let ab = v8::ArrayBuffer::with_backing_store(scope, &backing_store_shared); - Ok( - v8::Uint8Array::new(scope, ab, 0, buf_len) - .expect("Failed to create Uint8Array") - .into(), - ) - } -} diff --git a/serde_v8/magic/bytestring.rs b/serde_v8/magic/bytestring.rs deleted file mode 100644 index 3baa704e5..000000000 --- a/serde_v8/magic/bytestring.rs +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. -use super::transl8::FromV8; -use super::transl8::ToV8; -use crate::error::value_to_type_str; -use crate::magic::transl8::impl_magic; -use crate::Error; -use smallvec::SmallVec; -use std::mem::size_of; - -const USIZE2X: usize = size_of::<usize>() * 2; - -#[derive( - PartialEq, - Eq, - Clone, - Debug, - Default, - derive_more::Deref, - derive_more::DerefMut, - derive_more::AsRef, - derive_more::AsMut, -)] -#[as_mut(forward)] -#[as_ref(forward)] -pub struct ByteString(SmallVec<[u8; USIZE2X]>); -impl_magic!(ByteString); - -// const-assert that Vec<u8> and SmallVec<[u8; size_of::<usize>() * 2]> have a same size. -// Note from https://docs.rs/smallvec/latest/smallvec/#union - -// smallvec can still be larger than Vec if the inline buffer is -// larger than two machine words. -const _: () = - assert!(size_of::<Vec<u8>>() == size_of::<SmallVec<[u8; USIZE2X]>>()); - -impl ToV8 for ByteString { - fn to_v8<'a>( - &mut self, - scope: &mut v8::HandleScope<'a>, - ) -> Result<v8::Local<'a, v8::Value>, crate::Error> { - let v = - v8::String::new_from_one_byte(scope, self, v8::NewStringType::Normal) - .unwrap(); - Ok(v.into()) - } -} - -impl FromV8 for ByteString { - fn from_v8( - scope: &mut v8::HandleScope, - value: v8::Local<v8::Value>, - ) -> Result<Self, crate::Error> { - let v8str = v8::Local::<v8::String>::try_from(value) - .map_err(|_| Error::ExpectedString(value_to_type_str(value)))?; - if !v8str.contains_only_onebyte() { - return Err(Error::ExpectedLatin1); - } - let len = v8str.length(); - let mut buffer = SmallVec::with_capacity(len); - #[allow(clippy::uninit_vec)] - // SAFETY: we set length == capacity (see previous line), - // before immediately writing into that buffer and sanity check with an assert - unsafe { - buffer.set_len(len); - let written = v8str.write_one_byte( - scope, - &mut buffer, - 0, - v8::WriteOptions::NO_NULL_TERMINATION, - ); - assert!(written == len); - } - Ok(Self(buffer)) - } -} - -// smallvec does not impl From/Into traits -// like Vec<u8> does. So here we are. - -impl From<Vec<u8>> for ByteString { - fn from(vec: Vec<u8>) -> Self { - ByteString(SmallVec::from_vec(vec)) - } -} - -#[allow(clippy::from_over_into)] -impl Into<Vec<u8>> for ByteString { - fn into(self) -> Vec<u8> { - self.0.into_vec() - } -} - -impl From<&[u8]> for ByteString { - fn from(s: &[u8]) -> Self { - ByteString(SmallVec::from_slice(s)) - } -} - -impl From<&str> for ByteString { - fn from(s: &str) -> Self { - let v: Vec<u8> = s.into(); - ByteString::from(v) - } -} - -impl From<String> for ByteString { - fn from(s: String) -> Self { - ByteString::from(s.into_bytes()) - } -} diff --git a/serde_v8/magic/detached_buffer.rs b/serde_v8/magic/detached_buffer.rs deleted file mode 100644 index bc4b3de67..000000000 --- a/serde_v8/magic/detached_buffer.rs +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2018-2023 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::v8slice::to_ranged_buffer; -use super::v8slice::V8Slice; -use crate::error::value_to_type_str; -use crate::magic::transl8::impl_magic; - -// A buffer that detaches when deserialized from JS -pub struct DetachedBuffer(V8Slice); -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>( - &mut 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) - .map_err(|_| crate::Error::ExpectedBuffer(value_to_type_str(value)))?; - if !b.is_detachable() { - return Err(crate::Error::ExpectedDetachable(value_to_type_str(value))); - } - let store = b.get_backing_store(); - b.detach(None); // Detach - Ok(Self(V8Slice { store, range })) - } -} diff --git a/serde_v8/magic/external_pointer.rs b/serde_v8/magic/external_pointer.rs deleted file mode 100644 index e22e41a01..000000000 --- a/serde_v8/magic/external_pointer.rs +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. - -use std::ffi::c_void; - -use crate::error::value_to_type_str; - -use super::transl8::impl_magic; -use super::transl8::FromV8; -use super::transl8::ToV8; - -pub struct ExternalPointer(*mut c_void); - -// SAFETY: Nonblocking FFI is user controller and we must trust user to have it right. -unsafe impl Send for ExternalPointer {} -// SAFETY: Nonblocking FFI is user controller and we must trust user to have it right. -unsafe impl Sync for ExternalPointer {} - -impl_magic!(ExternalPointer); - -impl ToV8 for ExternalPointer { - fn to_v8<'a>( - &mut self, - scope: &mut v8::HandleScope<'a>, - ) -> Result<v8::Local<'a, v8::Value>, crate::Error> { - if self.0.is_null() { - Ok(v8::null(scope).into()) - } else { - Ok(v8::External::new(scope, self.0).into()) - } - } -} - -impl FromV8 for ExternalPointer { - fn from_v8( - _scope: &mut v8::HandleScope, - value: v8::Local<v8::Value>, - ) -> Result<Self, crate::Error> { - if value.is_null() { - Ok(ExternalPointer(std::ptr::null_mut())) - } else if let Ok(external) = v8::Local::<v8::External>::try_from(value) { - Ok(ExternalPointer(external.value())) - } else { - Err(crate::Error::ExpectedExternal(value_to_type_str(value))) - } - } -} - -impl From<*mut c_void> for ExternalPointer { - fn from(value: *mut c_void) -> Self { - ExternalPointer(value) - } -} - -impl From<*const c_void> for ExternalPointer { - fn from(value: *const c_void) -> Self { - ExternalPointer(value as *mut c_void) - } -} diff --git a/serde_v8/magic/global.rs b/serde_v8/magic/global.rs deleted file mode 100644 index 52b316fa5..000000000 --- a/serde_v8/magic/global.rs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. - -use crate::magic::transl8::impl_magic; -use crate::magic::transl8::FromV8; -use crate::magic::transl8::ToV8; - -pub struct Global { - pub v8_value: v8::Global<v8::Value>, -} -impl_magic!(Global); - -impl From<v8::Global<v8::Value>> for Global { - fn from(v8_value: v8::Global<v8::Value>) -> Self { - Self { v8_value } - } -} - -impl From<Global> for v8::Global<v8::Value> { - fn from(v: Global) -> Self { - v.v8_value - } -} - -impl ToV8 for Global { - fn to_v8<'a>( - &mut self, - scope: &mut v8::HandleScope<'a>, - ) -> Result<v8::Local<'a, v8::Value>, crate::Error> { - Ok(v8::Local::new(scope, self.v8_value.clone())) - } -} - -impl FromV8 for Global { - fn from_v8( - scope: &mut v8::HandleScope, - value: v8::Local<v8::Value>, - ) -> Result<Self, crate::Error> { - let global = v8::Global::new(scope, value); - Ok(global.into()) - } -} diff --git a/serde_v8/magic/mod.rs b/serde_v8/magic/mod.rs deleted file mode 100644 index 3e984527d..000000000 --- a/serde_v8/magic/mod.rs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. -pub mod any_value; -pub mod bigint; -pub mod buffer; -pub mod bytestring; -pub mod detached_buffer; -mod external_pointer; -mod global; -pub(super) mod rawbytes; -pub mod string_or_buffer; -pub mod transl8; -pub mod u16string; -pub mod v8slice; -mod value; -pub use external_pointer::ExternalPointer; -pub use global::Global; -pub use value::Value; diff --git a/serde_v8/magic/rawbytes.rs b/serde_v8/magic/rawbytes.rs deleted file mode 100644 index 2703c7756..000000000 --- a/serde_v8/magic/rawbytes.rs +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. -pub(crate) type AtomicPtr<T> = *mut T; -#[allow(unused)] -pub(crate) struct RawBytes { - ptr: *const u8, - len: usize, - // inlined "trait object" - data: AtomicPtr<()>, - vtable: &'static Vtable, -} - -impl RawBytes { - pub fn new_raw( - ptr: *const u8, - len: usize, - data: AtomicPtr<()>, - vtable: &'static Vtable, - ) -> bytes::Bytes { - RawBytes { - ptr, - len, - data, - vtable, - } - .into() - } -} - -// Validate some bytes::Bytes layout assumptions at compile time. -const _: () = { - assert!( - core::mem::size_of::<RawBytes>() == core::mem::size_of::<bytes::Bytes>(), - ); - assert!( - core::mem::align_of::<RawBytes>() == core::mem::align_of::<bytes::Bytes>(), - ); -}; - -#[allow(unused)] -pub(crate) struct Vtable { - /// fn(data, ptr, len) - pub clone: unsafe fn(&AtomicPtr<()>, *const u8, usize) -> bytes::Bytes, - /// fn(data, ptr, len) - /// - /// takes `Bytes` to value - pub to_vec: unsafe fn(&AtomicPtr<()>, *const u8, usize) -> Vec<u8>, - /// fn(data, ptr, len) - pub drop: unsafe fn(&mut AtomicPtr<()>, *const u8, usize), -} - -impl From<RawBytes> for bytes::Bytes { - fn from(b: RawBytes) -> Self { - // SAFETY: RawBytes has the same layout as bytes::Bytes - // this is tested below, both are composed of usize-d ptrs/values - // thus aren't currently subject to rust's field re-ordering to minimize padding - unsafe { std::mem::transmute(b) } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use std::mem; - - const HELLO: &str = "hello"; - - // ===== impl StaticVtable ===== - - const STATIC_VTABLE: Vtable = Vtable { - clone: static_clone, - drop: static_drop, - to_vec: static_to_vec, - }; - - unsafe fn static_clone( - _: &AtomicPtr<()>, - ptr: *const u8, - len: usize, - ) -> bytes::Bytes { - from_static(std::slice::from_raw_parts(ptr, len)).into() - } - - unsafe fn static_to_vec( - _: &AtomicPtr<()>, - ptr: *const u8, - len: usize, - ) -> Vec<u8> { - let slice = std::slice::from_raw_parts(ptr, len); - slice.to_vec() - } - - unsafe fn static_drop(_: &mut AtomicPtr<()>, _: *const u8, _: usize) { - // nothing to drop for &'static [u8] - } - - fn from_static(bytes: &'static [u8]) -> RawBytes { - RawBytes { - ptr: bytes.as_ptr(), - len: bytes.len(), - data: std::ptr::null_mut(), - vtable: &STATIC_VTABLE, - } - } - - #[test] - fn bytes_identity() { - let b1: bytes::Bytes = from_static(HELLO.as_bytes()).into(); - let b2 = bytes::Bytes::from_static(HELLO.as_bytes()); - assert_eq!(b1, b2); // Values are equal - } - - #[test] - fn bytes_layout() { - let u1: [usize; 4] = - // SAFETY: ensuring layout is the same - unsafe { mem::transmute(from_static(HELLO.as_bytes())) }; - let u2: [usize; 4] = - // SAFETY: ensuring layout is the same - unsafe { mem::transmute(bytes::Bytes::from_static(HELLO.as_bytes())) }; - assert_eq!(u1[..3], u2[..3]); // Struct bytes are equal besides Vtables - } -} diff --git a/serde_v8/magic/string_or_buffer.rs b/serde_v8/magic/string_or_buffer.rs deleted file mode 100644 index 986f7d32a..000000000 --- a/serde_v8/magic/string_or_buffer.rs +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. -use super::buffer::JsBuffer; -use super::transl8::FromV8; -use crate::error::value_to_type_str; -use crate::magic::transl8::impl_magic; -use crate::Error; -use std::ops::Deref; - -#[derive(Debug)] -pub enum StringOrBuffer { - Buffer(JsBuffer), - String(String), -} - -impl_magic!(StringOrBuffer); - -impl Deref for StringOrBuffer { - type Target = [u8]; - fn deref(&self) -> &Self::Target { - match self { - Self::Buffer(b) => b.as_ref(), - Self::String(s) => s.as_bytes(), - } - } -} - -impl<'a> TryFrom<&'a StringOrBuffer> for &'a str { - type Error = std::str::Utf8Error; - fn try_from(value: &'a StringOrBuffer) -> Result<Self, Self::Error> { - match value { - StringOrBuffer::String(s) => Ok(s.as_str()), - StringOrBuffer::Buffer(b) => std::str::from_utf8(b.as_ref()), - } - } -} - -impl FromV8 for StringOrBuffer { - fn from_v8( - scope: &mut v8::HandleScope, - value: v8::Local<v8::Value>, - ) -> Result<Self, crate::Error> { - if let Ok(buf) = JsBuffer::from_v8(scope, value) { - return Ok(Self::Buffer(buf)); - } else if let Ok(s) = crate::from_v8(scope, value) { - return Ok(Self::String(s)); - } - Err(Error::ExpectedBuffer(value_to_type_str(value))) - } -} - -impl From<StringOrBuffer> for bytes::Bytes { - fn from(sob: StringOrBuffer) -> Self { - match sob { - StringOrBuffer::Buffer(b) => b.into(), - StringOrBuffer::String(s) => s.into_bytes().into(), - } - } -} diff --git a/serde_v8/magic/transl8.rs b/serde_v8/magic/transl8.rs deleted file mode 100644 index 3a8d0c358..000000000 --- a/serde_v8/magic/transl8.rs +++ /dev/null @@ -1,165 +0,0 @@ -// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. - -//! Transerialization extends the set of serde-compatible types (for given de/serializers). -//! By "hackishly" transmuting references across serde boundaries as u64s. -//! Type-safety is enforced using special struct names for each "magic type". -//! Memory-safety relies on transerialized values being "pinned" during de/serialization. - -pub(crate) const MAGIC_FIELD: &str = "$__v8_magic_field"; - -pub(crate) trait MagicType { - const NAME: &'static str; - const MAGIC_NAME: &'static str; -} - -pub(crate) trait ToV8 { - fn to_v8<'a>( - &mut self, - scope: &mut v8::HandleScope<'a>, - ) -> Result<v8::Local<'a, v8::Value>, crate::Error>; -} - -pub(crate) trait FromV8: Sized { - fn from_v8( - scope: &mut v8::HandleScope, - value: v8::Local<v8::Value>, - ) -> Result<Self, crate::Error>; -} - -pub(crate) fn magic_serialize<T, S>( - serializer: S, - x: &T, -) -> Result<S::Ok, S::Error> -where - S: serde::Serializer, - T: MagicType, -{ - use serde::ser::SerializeStruct; - - let mut s = serializer.serialize_struct(T::MAGIC_NAME, 1)?; - let ptr = opaque_send(x); - s.serialize_field(MAGIC_FIELD, &ptr)?; - s.end() -} - -pub(crate) fn magic_deserialize<'de, T, D>( - deserializer: D, -) -> Result<T, D::Error> -where - D: serde::Deserializer<'de>, - T: MagicType, -{ - struct ValueVisitor<T> { - p1: std::marker::PhantomData<T>, - } - - impl<'de, T: MagicType> serde::de::Visitor<'de> for ValueVisitor<T> { - type Value = T; - - fn expecting( - &self, - formatter: &mut std::fmt::Formatter, - ) -> std::fmt::Result { - formatter.write_str("a ")?; - formatter.write_str(T::NAME) - } - - fn visit_u64<E>(self, ptr: u64) -> Result<Self::Value, E> - where - E: serde::de::Error, - { - // SAFETY: opaque ptr originates from visit_magic, which forgets ownership so we can take it - Ok(unsafe { opaque_take(ptr) }) - } - } - - deserializer.deserialize_struct( - T::MAGIC_NAME, - &[MAGIC_FIELD], - ValueVisitor::<T> { - p1: std::marker::PhantomData, - }, - ) -} - -pub(crate) fn visit_magic<'de, T, V, E>(visitor: V, x: T) -> Result<V::Value, E> -where - V: serde::de::Visitor<'de>, - E: serde::de::Error, -{ - let y = visitor.visit_u64::<E>(opaque_send(&x)); - std::mem::forget(x); - y -} - -/// Constructs an "opaque" ptr from a reference to transerialize -pub(crate) fn opaque_send<T: Sized>(x: &T) -> u64 { - (x as *const T) as u64 -} - -/// Copies an "opaque" ptr from a reference to an opaque ptr (transerialized) -/// NOTE: ptr-to-ptr, extra indirection -pub(crate) unsafe fn opaque_recv<T: ?Sized>(ptr: &T) -> u64 { - *(ptr as *const T as *const u64) -} - -/// Transmutes an "opaque" ptr back into a reference -pub(crate) unsafe fn opaque_deref_mut<'a, T>(ptr: u64) -> &'a mut T { - std::mem::transmute(ptr as usize) -} - -/// Transmutes & copies the value from the "opaque" ptr -/// NOTE: takes ownership & requires other end to forget its ownership -pub(crate) unsafe fn opaque_take<T>(ptr: u64) -> T { - std::mem::transmute_copy::<T, T>(std::mem::transmute(ptr as usize)) -} - -macro_rules! impl_magic { - ($t:ty) => { - impl crate::magic::transl8::MagicType for $t { - const NAME: &'static str = stringify!($t); - const MAGIC_NAME: &'static str = concat!("$__v8_magic_", stringify!($t)); - } - - impl serde::Serialize for $t { - fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> - where - S: serde::Serializer, - { - crate::magic::transl8::magic_serialize(serializer, self) - } - } - - impl<'de> serde::Deserialize<'de> for $t { - fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> - where - D: serde::Deserializer<'de>, - { - crate::magic::transl8::magic_deserialize(deserializer) - } - } - }; -} -pub(crate) use impl_magic; - -macro_rules! impl_wrapper { - ($i:item) => { - #[derive( - PartialEq, - Eq, - Clone, - Debug, - Default, - derive_more::Deref, - derive_more::DerefMut, - derive_more::AsRef, - derive_more::AsMut, - derive_more::From, - )] - #[as_mut(forward)] - #[as_ref(forward)] - #[from(forward)] - $i - }; -} -pub(crate) use impl_wrapper; diff --git a/serde_v8/magic/u16string.rs b/serde_v8/magic/u16string.rs deleted file mode 100644 index 04d742da9..000000000 --- a/serde_v8/magic/u16string.rs +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. - -use crate::error::value_to_type_str; -use crate::Error; - -use super::transl8::impl_magic; -use super::transl8::impl_wrapper; -use super::transl8::FromV8; -use super::transl8::ToV8; - -impl_wrapper!( - pub struct U16String(Vec<u16>); -); -impl_magic!(U16String); - -impl ToV8 for U16String { - fn to_v8<'a>( - &mut self, - scope: &mut v8::HandleScope<'a>, - ) -> Result<v8::Local<'a, v8::Value>, crate::Error> { - let maybe_v = - v8::String::new_from_two_byte(scope, self, v8::NewStringType::Normal); - - // 'new_from_two_byte' can return 'None' if buffer length > kMaxLength. - if let Some(v) = maybe_v { - Ok(v.into()) - } else { - Err(Error::Message(String::from( - "Cannot allocate String from UTF-16: buffer exceeds maximum length.", - ))) - } - } -} - -impl FromV8 for U16String { - fn from_v8( - scope: &mut v8::HandleScope, - value: v8::Local<v8::Value>, - ) -> Result<Self, crate::Error> { - let v8str = v8::Local::<v8::String>::try_from(value) - .map_err(|_| Error::ExpectedString(value_to_type_str(value)))?; - let len = v8str.length(); - let mut buffer = Vec::with_capacity(len); - #[allow(clippy::uninit_vec)] - // SAFETY: we set length == capacity (see previous line), - // before immediately writing into that buffer and sanity check with an assert - unsafe { - buffer.set_len(len); - let written = v8str.write( - scope, - &mut buffer, - 0, - v8::WriteOptions::NO_NULL_TERMINATION, - ); - assert!(written == len); - } - Ok(buffer.into()) - } -} diff --git a/serde_v8/magic/v8slice.rs b/serde_v8/magic/v8slice.rs deleted file mode 100644 index 2b103f1c9..000000000 --- a/serde_v8/magic/v8slice.rs +++ /dev/null @@ -1,181 +0,0 @@ -// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. - -use std::ops::Deref; -use std::ops::DerefMut; -use std::ops::Range; -use std::rc::Rc; - -use crate::error::value_to_type_str; - -use super::rawbytes; -use super::transl8::FromV8; - -/// A V8Slice encapsulates a slice that's been borrowed from a JavaScript -/// ArrayBuffer object. JavaScript objects can normally be garbage collected, -/// but the existence of a V8Slice inhibits this until it is dropped. It -/// behaves much like an Arc<[u8]>. -/// -/// # Cloning -/// Cloning a V8Slice does not clone the contents of the buffer, -/// it creates a new reference to that buffer. -/// -/// To actually clone the contents of the buffer do -/// `let copy = Vec::from(&*zero_copy_buf);` -#[derive(Clone)] -pub struct V8Slice { - pub(crate) store: v8::SharedRef<v8::BackingStore>, - pub(crate) range: Range<usize>, -} - -// SAFETY: unsafe trait must have unsafe implementation -unsafe impl Send for V8Slice {} - -impl V8Slice { - fn as_slice(&self) -> &[u8] { - // SAFETY: v8::SharedRef<v8::BackingStore> is similar to Arc<[u8]>, - // it points to a fixed continuous slice of bytes on the heap. - // We assume it's initialized and thus safe to read (though may not contain meaningful data) - unsafe { &*(&self.store[self.range.clone()] as *const _ as *const [u8]) } - } - - fn as_slice_mut(&mut self) -> &mut [u8] { - #[allow(clippy::cast_ref_to_mut)] - // SAFETY: v8::SharedRef<v8::BackingStore> is similar to Arc<[u8]>, - // it points to a fixed continuous slice of bytes on the heap. - // It's safe-ish to mutate concurrently because it can not be - // shrunk/grown/moved/reallocated, thus avoiding dangling refs (unlike a Vec). - // Concurrent writes can't lead to meaningful structural invalidation - // since we treat them as opaque buffers / "bags of bytes", - // concurrent mutation is simply an accepted fact of life. - // And in practice V8Slices also do not have overallping read/write phases. - // TLDR: permissive interior mutability on slices of bytes is "fine" - unsafe { - &mut *(&self.store[self.range.clone()] as *const _ as *mut [u8]) - } - } -} - -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 let Ok(view) = v8::Local::<v8::ArrayBufferView>::try_from(value) { - 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 V8Slice { - fn from_v8( - scope: &mut v8::HandleScope, - value: v8::Local<v8::Value>, - ) -> Result<Self, crate::Error> { - match to_ranged_buffer(scope, value) { - Ok((b, range)) => { - let store = b.get_backing_store(); - if store.is_resizable_by_user_javascript() { - Err(crate::Error::ResizableBackingStoreNotSupported) - } else if store.is_shared() { - Err(crate::Error::ExpectedBuffer(value_to_type_str(value))) - } else { - Ok(V8Slice { store, range }) - } - } - Err(_) => Err(crate::Error::ExpectedBuffer(value_to_type_str(value))), - } - } -} - -impl Deref for V8Slice { - type Target = [u8]; - fn deref(&self) -> &[u8] { - self.as_slice() - } -} - -impl DerefMut for V8Slice { - fn deref_mut(&mut self) -> &mut [u8] { - self.as_slice_mut() - } -} - -impl AsRef<[u8]> for V8Slice { - fn as_ref(&self) -> &[u8] { - self.as_slice() - } -} - -impl AsMut<[u8]> for V8Slice { - fn as_mut(&mut self) -> &mut [u8] { - self.as_slice_mut() - } -} - -// Implement V8Slice -> bytes::Bytes -impl V8Slice { - fn rc_into_byte_parts(self: Rc<Self>) -> (*const u8, usize, *mut V8Slice) { - let (ptr, len) = { - let slice = self.as_ref(); - (slice.as_ptr(), slice.len()) - }; - let rc_raw = Rc::into_raw(self); - let data = rc_raw as *mut V8Slice; - (ptr, len, data) - } -} - -impl From<V8Slice> for bytes::Bytes { - fn from(v8slice: V8Slice) -> Self { - let (ptr, len, data) = Rc::new(v8slice).rc_into_byte_parts(); - rawbytes::RawBytes::new_raw(ptr, len, data.cast(), &V8SLICE_VTABLE) - } -} - -// NOTE: in the limit we could avoid extra-indirection and use the C++ shared_ptr -// but we can't store both the underlying data ptr & ctrl ptr ... so instead we -// use a shared rust ptr (Rc/Arc) that itself controls the C++ shared_ptr -const V8SLICE_VTABLE: rawbytes::Vtable = rawbytes::Vtable { - clone: v8slice_clone, - drop: v8slice_drop, - to_vec: v8slice_to_vec, -}; - -unsafe fn v8slice_clone( - data: &rawbytes::AtomicPtr<()>, - ptr: *const u8, - len: usize, -) -> bytes::Bytes { - let rc = Rc::from_raw(*data as *const V8Slice); - let (_, _, data) = rc.clone().rc_into_byte_parts(); - std::mem::forget(rc); - // NOTE: `bytes::Bytes` does bounds checking so we trust its ptr, len inputs - // and must use them to allow cloning Bytes it has sliced - rawbytes::RawBytes::new_raw(ptr, len, data.cast(), &V8SLICE_VTABLE) -} - -unsafe fn v8slice_to_vec( - data: &rawbytes::AtomicPtr<()>, - ptr: *const u8, - len: usize, -) -> Vec<u8> { - let rc = Rc::from_raw(*data as *const V8Slice); - std::mem::forget(rc); - // NOTE: `bytes::Bytes` does bounds checking so we trust its ptr, len inputs - // and must use them to allow cloning Bytes it has sliced - Vec::from_raw_parts(ptr as _, len, len) -} - -unsafe fn v8slice_drop( - data: &mut rawbytes::AtomicPtr<()>, - _: *const u8, - _: usize, -) { - drop(Rc::from_raw(*data as *const V8Slice)) -} diff --git a/serde_v8/magic/value.rs b/serde_v8/magic/value.rs deleted file mode 100644 index 0333d75bc..000000000 --- a/serde_v8/magic/value.rs +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. - -use crate::magic::transl8::impl_magic; -use crate::magic::transl8::FromV8; -use crate::magic::transl8::ToV8; -use std::mem::transmute; - -/// serde_v8::Value allows passing through `v8::Value`s untouched -/// when de/serializing & allows mixing rust & v8 values in structs, tuples... -// -// SAFETY: caveat emptor, the rust-compiler can no longer link lifetimes to their -// original scope, you must take special care in ensuring your handles don't outlive their scope -pub struct Value<'s> { - pub v8_value: v8::Local<'s, v8::Value>, -} -impl_magic!(Value<'_>); - -impl<'s> From<v8::Local<'s, v8::Value>> for Value<'s> { - fn from(v8_value: v8::Local<'s, v8::Value>) -> Self { - Self { v8_value } - } -} - -impl<'s> From<Value<'s>> for v8::Local<'s, v8::Value> { - fn from(v: Value<'s>) -> Self { - v.v8_value - } -} - -impl ToV8 for Value<'_> { - fn to_v8<'a>( - &mut self, - _scope: &mut v8::HandleScope<'a>, - ) -> Result<v8::Local<'a, v8::Value>, crate::Error> { - // SAFETY: not fully safe, since lifetimes are detached from original scope - Ok(unsafe { transmute(self.v8_value) }) - } -} - -impl FromV8 for Value<'_> { - fn from_v8( - _scope: &mut v8::HandleScope, - value: v8::Local<v8::Value>, - ) -> Result<Self, crate::Error> { - // SAFETY: not fully safe, since lifetimes are detached from original scope - Ok(unsafe { transmute::<Value, Value>(value.into()) }) - } -} |