From ebc8a3ccf206cf7cd29d813fedf5e8f4507113d5 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Thu, 30 Jun 2022 08:47:18 +0530 Subject: [PATCH] perf(serde_v8): smallvec ByteString (#15008) --- Cargo.lock | 1 + serde_v8/Cargo.toml | 1 + serde_v8/magic/bytestring.rs | 59 +++++++++++++++++++++++++++++++++--- 3 files changed, 56 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 07449b7a24..b3aa747485 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3839,6 +3839,7 @@ dependencies = [ "derive_more", "serde", "serde_json", + "smallvec", "v8", ] diff --git a/serde_v8/Cargo.toml b/serde_v8/Cargo.toml index 4f4d2d349c..4090743b96 100644 --- a/serde_v8/Cargo.toml +++ b/serde_v8/Cargo.toml @@ -16,6 +16,7 @@ path = "lib.rs" bytes = "1" derive_more = "0.99.17" serde = { version = "1.0.136", features = ["derive"] } +smallvec = { version = "1.8", features = ["union"] } v8 = "0.44.2" [dev-dependencies] diff --git a/serde_v8/magic/bytestring.rs b/serde_v8/magic/bytestring.rs index d6f3cb1740..3efb56f6aa 100644 --- a/serde_v8/magic/bytestring.rs +++ b/serde_v8/magic/bytestring.rs @@ -1,11 +1,32 @@ // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. use super::transl8::{FromV8, ToV8}; -use crate::magic::transl8::{impl_magic, impl_wrapper}; +use crate::magic::transl8::impl_magic; use crate::Error; +use smallvec::SmallVec; +use std::mem::size_of; -impl_wrapper! { pub struct ByteString(Vec); } +#[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; 16]>); impl_magic!(ByteString); +// const-assert that Vec and SmallVec<[u8; 16]> 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::>() == size_of::>()); + impl ToV8 for ByteString { fn to_v8<'a>( &self, @@ -29,7 +50,7 @@ impl FromV8 for ByteString { return Err(Error::ExpectedLatin1); } let len = v8str.length(); - let mut buffer = Vec::with_capacity(len); + let mut buffer = SmallVec::with_capacity(len); // SAFETY: we set length == capacity (see previous line), // before immediately writing into that buffer and sanity check with an assert #[allow(clippy::uninit_vec)] @@ -43,13 +64,41 @@ impl FromV8 for ByteString { ); assert!(written == len); } - Ok(buffer.into()) + Ok(Self(buffer)) + } +} + +// smallvec does not impl From/Into traits +// like Vec does. So here we are. + +impl From> for ByteString { + fn from(vec: Vec) -> Self { + ByteString(SmallVec::from_vec(vec)) } } #[allow(clippy::from_over_into)] impl Into> for ByteString { fn into(self) -> Vec { - self.0 + 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 = s.into(); + ByteString::from(v) + } +} + +impl From for ByteString { + fn from(s: String) -> Self { + ByteString::from(s.into_bytes()) } }