From d70d8a70fcf4408f10cc72fff40c1bd5800108b9 Mon Sep 17 00:00:00 2001 From: Aaron O'Mullan Date: Sat, 2 Apr 2022 14:37:11 +0200 Subject: [PATCH] experiment(serde_v8): derive_more enabled opaque wrappers (#14096) --- Cargo.lock | 1 + ext/fetch/lib.rs | 6 +-- ext/http/compressible.rs | 10 ++--- ext/http/lib.rs | 23 +++++------ ext/net/ops_tls.rs | 6 +-- ext/web/lib.rs | 13 +++--- serde_v8/Cargo.toml | 1 + serde_v8/benches/ser.rs | 4 +- serde_v8/magic/bytestring.rs | 80 ++---------------------------------- serde_v8/magic/transl8.rs | 22 ++++++++++ serde_v8/magic/u16string.rs | 48 +++------------------- serde_v8/tests/de.rs | 6 +-- serde_v8/tests/magic.rs | 4 +- 13 files changed, 61 insertions(+), 163 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0d7affd15d..766c7edf45 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3709,6 +3709,7 @@ name = "serde_v8" version = "0.38.0" dependencies = [ "bencher", + "derive_more", "serde", "serde_bytes", "serde_json", diff --git a/ext/fetch/lib.rs b/ext/fetch/lib.rs index b744a9bbd6..c216d53fa8 100644 --- a/ext/fetch/lib.rs +++ b/ext/fetch/lib.rs @@ -395,11 +395,7 @@ pub async fn op_fetch_send( let url = res.url().to_string(); let mut res_headers = Vec::new(); for (key, val) in res.headers().iter() { - let key_bytes: &[u8] = key.as_ref(); - res_headers.push(( - ByteString(key_bytes.to_owned()), - ByteString(val.as_bytes().to_owned()), - )); + res_headers.push((key.as_str().into(), val.as_bytes().into())); } let stream: BytesStream = Box::pin(res.bytes_stream().map(|r| { diff --git a/ext/http/compressible.rs b/ext/http/compressible.rs index 21cd42c762..b85f4a325e 100644 --- a/ext/http/compressible.rs +++ b/ext/http/compressible.rs @@ -646,15 +646,13 @@ mod tests { #[test] fn non_compressible_content_type() { - assert!(!is_content_compressible(Some(&ByteString( - b"application/vnd.deno+json".to_vec() - )))); + assert!(!is_content_compressible(Some( + &"application/vnd.deno+json".into() + ))); } #[test] fn ncompressible_content_type() { - assert!(is_content_compressible(Some(&ByteString( - b"application/json".to_vec() - )))); + assert!(is_content_compressible(Some(&"application/json".into()))); } } diff --git a/ext/http/lib.rs b/ext/http/lib.rs index d636e206cb..f0b4588c61 100644 --- a/ext/http/lib.rs +++ b/ext/http/lib.rs @@ -470,15 +470,12 @@ fn req_headers( } else { let name: &[u8] = name.as_ref(); let value = value.as_bytes(); - headers.push((ByteString(name.to_owned()), ByteString(value.to_owned()))); + headers.push((name.into(), value.into())); } } if !cookies.is_empty() { - headers.push(( - ByteString("cookie".as_bytes().to_owned()), - ByteString(cookies.join(cookie_sep)), - )); + headers.push(("cookie".into(), cookies.join(cookie_sep).into())); } headers @@ -548,7 +545,7 @@ async fn op_http_write_headers( vary_header = Some(value); continue; } - builder = builder.header(key.as_ref(), value.as_ref()); + builder = builder.header(key.as_slice(), value.as_slice()); } if headers_allow_compression { @@ -566,7 +563,7 @@ async fn op_http_write_headers( // data to make sure cache services do not serve uncompressed data to // clients that support compression. let vary_value = if let Some(value) = vary_header { - if let Ok(value_str) = std::str::from_utf8(value.as_ref()) { + if let Ok(value_str) = std::str::from_utf8(value.as_slice()) { if !value_str.to_lowercase().contains("accept-encoding") { format!("Accept-Encoding, {}", value_str) } else { @@ -598,14 +595,14 @@ async fn op_http_write_headers( // If user provided a ETag header for uncompressed data, we need to // ensure it is a Weak Etag header ("W/"). if let Some(value) = etag_header { - if let Ok(value_str) = std::str::from_utf8(value.as_ref()) { + if let Ok(value_str) = std::str::from_utf8(value.as_slice()) { if !value_str.starts_with("W/") { builder = builder.header("etag", format!("W/{}", value_str)); } else { - builder = builder.header("etag", value.as_ref()); + builder = builder.header("etag", value.as_slice()); } } else { - builder = builder.header("etag", value.as_ref()); + builder = builder.header("etag", value.as_slice()); } } @@ -636,7 +633,7 @@ async fn op_http_write_headers( } } else { if let Some(value) = etag_header { - builder = builder.header("etag", value.as_ref()); + builder = builder.header("etag", value.as_slice()); } // If a buffer was passed, but isn't compressible, we use it to // construct a response body. @@ -651,10 +648,10 @@ async fn op_http_write_headers( // Set the user provided ETag & Vary headers for a streaming response if let Some(value) = etag_header { - builder = builder.header("etag", value.as_ref()); + builder = builder.header("etag", value.as_slice()); } if let Some(value) = vary_header { - builder = builder.header("vary", value.as_ref()); + builder = builder.header("vary", value.as_slice()); } let (body_tx, body_rx) = Body::channel(); diff --git a/ext/net/ops_tls.rs b/ext/net/ops_tls.rs index 74301292ba..d6b83e6e8b 100644 --- a/ext/net/ops_tls.rs +++ b/ext/net/ops_tls.rs @@ -156,11 +156,7 @@ impl TlsStream { } fn get_alpn_protocol(&mut self) -> Option { - self - .inner_mut() - .tls - .alpn_protocol() - .map(|s| ByteString(s.to_owned())) + self.inner_mut().tls.alpn_protocol().map(|s| s.into()) } } diff --git a/ext/web/lib.rs b/ext/web/lib.rs index 21fa285ba3..423e53c510 100644 --- a/ext/web/lib.rs +++ b/ext/web/lib.rs @@ -129,8 +129,7 @@ fn op_base64_decode(input: String) -> Result { } #[op] -fn op_base64_atob(s: ByteString) -> Result { - let mut s = s.0; +fn op_base64_atob(mut s: ByteString) -> Result { s.retain(|c| !c.is_ascii_whitespace()); // If padding is expected, fail if not 4-byte aligned @@ -140,7 +139,7 @@ fn op_base64_atob(s: ByteString) -> Result { ); } - Ok(ByteString(b64_decode(&s)?)) + Ok(b64_decode(&s)?.into()) } fn b64_decode(input: &[u8]) -> Result, AnyError> { @@ -185,7 +184,7 @@ fn op_base64_encode(s: ZeroCopyBuf) -> Result { #[op] fn op_base64_btoa(s: ByteString) -> Result { - Ok(b64_encode(&s)) + Ok(b64_encode(s)) } fn b64_encode(s: impl AsRef<[u8]>) -> String { @@ -270,7 +269,7 @@ fn op_encoding_decode( .max_utf16_buffer_length(data.len()) .ok_or_else(|| range_error("Value too large to decode."))?; - let mut output = U16String::with_zeroes(max_buffer_length); + let mut output = vec![0; max_buffer_length]; if fatal { let (result, _, written) = @@ -278,7 +277,7 @@ fn op_encoding_decode( match result { DecoderResult::InputEmpty => { output.truncate(written); - Ok(output) + Ok(output.into()) } DecoderResult::OutputFull => { Err(range_error("Provided buffer too small.")) @@ -293,7 +292,7 @@ fn op_encoding_decode( match result { CoderResult::InputEmpty => { output.truncate(written); - Ok(output) + Ok(output.into()) } CoderResult::OutputFull => Err(range_error("Provided buffer too small.")), } diff --git a/serde_v8/Cargo.toml b/serde_v8/Cargo.toml index 10f39ddf7e..54dded27c7 100644 --- a/serde_v8/Cargo.toml +++ b/serde_v8/Cargo.toml @@ -13,6 +13,7 @@ description = "Rust to V8 serialization and deserialization" path = "lib.rs" [dependencies] +derive_more = "0.99.17" serde = { version = "1.0.130", features = ["derive"] } serde_bytes = "0.11" v8 = "0.41.0" diff --git a/serde_v8/benches/ser.rs b/serde_v8/benches/ser.rs index 3ba95fc2a5..1bfc6fadcd 100644 --- a/serde_v8/benches/ser.rs +++ b/serde_v8/benches/ser.rs @@ -90,7 +90,7 @@ fn ser_struct_v8_manual(b: &mut Bencher) { fn ser_bstr_12_b(b: &mut Bencher) { serdo(|scope| { - let bstr = ByteString("hello world\n".to_owned().into_bytes()); + let bstr = ByteString::from("hello world\n"); b.iter(|| { let _ = serde_v8::to_v8(scope, &bstr).unwrap(); }); @@ -101,7 +101,7 @@ fn ser_bstr_1024_b(b: &mut Bencher) { serdo(|scope| { let mut s = "hello world\n".repeat(100); s.truncate(1024); - let bstr = ByteString(s.into_bytes()); + let bstr = ByteString::from(s); b.iter(|| { let _ = serde_v8::to_v8(scope, &bstr).unwrap(); }); diff --git a/serde_v8/magic/bytestring.rs b/serde_v8/magic/bytestring.rs index 43ac54b976..a4c664b295 100644 --- a/serde_v8/magic/bytestring.rs +++ b/serde_v8/magic/bytestring.rs @@ -1,85 +1,11 @@ // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. - -use std::ops::{Deref, DerefMut}; - use super::transl8::{FromV8, ToV8}; -use crate::magic::transl8::impl_magic; +use crate::magic::transl8::{impl_magic, impl_wrapper}; use crate::Error; -#[derive(PartialEq, Eq, Clone, Debug)] -pub struct ByteString(pub Vec); +impl_wrapper! { pub struct ByteString(Vec); } impl_magic!(ByteString); -impl ByteString { - pub fn new() -> ByteString { - ByteString(Vec::new()) - } - - pub fn with_capacity(capacity: usize) -> ByteString { - ByteString(Vec::with_capacity(capacity)) - } - - pub fn capacity(&self) -> usize { - self.0.capacity() - } - - pub fn reserve(&mut self, additional: usize) { - self.0.reserve(additional) - } - - pub fn reserve_exact(&mut self, additional: usize) { - self.0.reserve_exact(additional) - } - - pub fn shrink_to_fit(&mut self) { - self.0.shrink_to_fit() - } - - pub fn truncate(&mut self, len: usize) { - self.0.truncate(len) - } - - pub fn push(&mut self, value: u8) { - self.0.push(value) - } - - pub fn pop(&mut self) -> Option { - self.0.pop() - } -} - -impl Default for ByteString { - fn default() -> Self { - ByteString::new() - } -} - -impl Deref for ByteString { - type Target = [u8]; - - fn deref(&self) -> &[u8] { - self.0.deref() - } -} - -impl DerefMut for ByteString { - fn deref_mut(&mut self) -> &mut [u8] { - self.0.deref_mut() - } -} - -impl AsRef<[u8]> for ByteString { - fn as_ref(&self) -> &[u8] { - self.0.as_ref() - } -} - -impl AsMut<[u8]> for ByteString { - fn as_mut(&mut self) -> &mut [u8] { - self.0.as_mut() - } -} - impl ToV8 for ByteString { fn to_v8<'a>( &self, @@ -117,6 +43,6 @@ impl FromV8 for ByteString { ); assert!(written == len); } - Ok(ByteString(buffer)) + Ok(buffer.into()) } } diff --git a/serde_v8/magic/transl8.rs b/serde_v8/magic/transl8.rs index 458b821299..d08be468b6 100644 --- a/serde_v8/magic/transl8.rs +++ b/serde_v8/magic/transl8.rs @@ -141,3 +141,25 @@ macro_rules! impl_magic { }; } 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 index 39ebf88d9e..c1d080ac74 100644 --- a/serde_v8/magic/u16string.rs +++ b/serde_v8/magic/u16string.rs @@ -1,49 +1,11 @@ -use crate::magic::transl8::impl_magic; +use super::transl8::{impl_magic, impl_wrapper, FromV8, ToV8}; use crate::Error; -use std::ops::{Deref, DerefMut}; -use super::transl8::{FromV8, ToV8}; - -#[derive(Default, PartialEq, Eq, Debug)] -pub struct U16String(pub Vec); +impl_wrapper!( + pub struct U16String(Vec); +); impl_magic!(U16String); -impl U16String { - pub fn with_zeroes(length: usize) -> U16String { - U16String(vec![0u16; length]) - } - - pub fn truncate(&mut self, new_length: usize) { - self.0.truncate(new_length); - self.0.shrink_to_fit() - } -} - -impl Deref for U16String { - type Target = [u16]; - fn deref(&self) -> &[u16] { - self.0.deref() - } -} - -impl DerefMut for U16String { - fn deref_mut(&mut self) -> &mut [u16] { - self.0.deref_mut() - } -} - -impl AsRef<[u16]> for U16String { - fn as_ref(&self) -> &[u16] { - self.0.as_ref() - } -} - -impl AsMut<[u16]> for U16String { - fn as_mut(&mut self) -> &mut [u16] { - self.0.as_mut() - } -} - impl ToV8 for U16String { fn to_v8<'a>( &self, @@ -78,6 +40,6 @@ impl FromV8 for U16String { ); assert!(written == len); } - Ok(U16String(buffer)) + Ok(buffer.into()) } } diff --git a/serde_v8/tests/de.rs b/serde_v8/tests/de.rs index 0c784acedd..37fc718a1d 100644 --- a/serde_v8/tests/de.rs +++ b/serde_v8/tests/de.rs @@ -313,7 +313,7 @@ detest!( } ); -detest!(de_bstr, ByteString, "'hello'", ByteString("hello".into())); +detest!(de_bstr, ByteString, "'hello'", "hello".into()); defail!(defail_bstr, ByteString, "'👋bye'", |e| e == Err(Error::ExpectedLatin1)); @@ -321,11 +321,11 @@ detest!( de_u16str, U16String, "'hello'", - U16String("hello".encode_utf16().collect()) + "hello".encode_utf16().collect::>().into() ); detest!( de_u16str_non_latin1, U16String, "'👋bye'", - U16String("👋bye".encode_utf16().collect()) + "👋bye".encode_utf16().collect::>().into() ); diff --git a/serde_v8/tests/magic.rs b/serde_v8/tests/magic.rs index 02fa41a68a..c65c36b60e 100644 --- a/serde_v8/tests/magic.rs +++ b/serde_v8/tests/magic.rs @@ -145,7 +145,7 @@ fn magic_byte_string() { let rust_reflex: serde_v8::ByteString = serde_v8::from_v8(scope, v8_string).unwrap(); assert_eq!( - rust_reflex.as_ref(), + rust_reflex.as_slice(), b"test \0\t\n\r\x7F\x80\xE1\xFE\xC6\xF1" ); @@ -164,7 +164,7 @@ fn magic_byte_string() { // ByteString to JS string let expected = "a\x00sf:~\x7Fá\u{009C}þ\u{008A}"; let buf: Vec = b"a\x00sf:~\x7F\xE1\x9C\xFE\x8A".as_ref().into(); - let zbuf = serde_v8::ByteString(buf); + let zbuf = serde_v8::ByteString::from(buf); let v8_value = serde_v8::to_v8(scope, zbuf).unwrap(); let key = serde_v8::to_v8(scope, "actual").unwrap(); global.set(scope, key, v8_value);