serde_v8/magic/
bytestring.rs

1// Copyright 2018-2025 the Deno authors. MIT license.
2
3use std::mem::size_of;
4use std::ops::Deref;
5use std::ops::DerefMut;
6
7use smallvec::SmallVec;
8
9use super::transl8::FromV8;
10use super::transl8::ToV8;
11use crate::Error;
12use crate::magic::transl8::impl_magic;
13
14const USIZE2X: usize = size_of::<usize>() * 2;
15
16#[derive(PartialEq, Eq, Clone, Debug, Default)]
17pub struct ByteString(SmallVec<[u8; USIZE2X]>);
18impl_magic!(ByteString);
19
20impl Deref for ByteString {
21  type Target = SmallVec<[u8; USIZE2X]>;
22
23  fn deref(&self) -> &Self::Target {
24    &self.0
25  }
26}
27
28impl DerefMut for ByteString {
29  fn deref_mut(&mut self) -> &mut Self::Target {
30    &mut self.0
31  }
32}
33
34impl AsRef<[u8]> for ByteString {
35  fn as_ref(&self) -> &[u8] {
36    &self.0
37  }
38}
39
40impl AsMut<[u8]> for ByteString {
41  fn as_mut(&mut self) -> &mut [u8] {
42    &mut self.0
43  }
44}
45
46// const-assert that Vec<u8> and SmallVec<[u8; size_of::<usize>() * 2]> have a same size.
47// Note from https://docs.rs/smallvec/latest/smallvec/#union -
48//   smallvec can still be larger than Vec if the inline buffer is
49//   larger than two machine words.
50const _: () =
51  assert!(size_of::<Vec<u8>>() == size_of::<SmallVec<[u8; USIZE2X]>>());
52
53impl ToV8 for ByteString {
54  fn to_v8<'scope, 'i>(
55    &self,
56    scope: &mut v8::PinScope<'scope, 'i>,
57  ) -> Result<v8::Local<'scope, v8::Value>, crate::Error> {
58    let v =
59      v8::String::new_from_one_byte(scope, self, v8::NewStringType::Normal)
60        .unwrap();
61    Ok(v.into())
62  }
63}
64
65impl FromV8 for ByteString {
66  fn from_v8<'scope, 'i>(
67    scope: &mut v8::PinScope,
68    value: v8::Local<'scope, v8::Value>,
69  ) -> Result<Self, crate::Error> {
70    let v8str = v8::Local::<v8::String>::try_from(value)
71      .map_err(|_| Error::ExpectedString(value.type_repr()))?;
72    if !v8str.contains_only_onebyte() {
73      return Err(Error::ExpectedLatin1);
74    }
75    let len = v8str.length();
76    let mut buffer = SmallVec::with_capacity(len);
77    #[allow(clippy::uninit_vec)]
78    // SAFETY: we set length == capacity (see previous line),
79    // before immediately writing into that buffer and sanity check with an assert
80    unsafe {
81      buffer.set_len(len);
82      v8str.write_one_byte_v2(scope, 0, &mut buffer, v8::WriteFlags::empty());
83    }
84    Ok(Self(buffer))
85  }
86}
87
88// smallvec does not impl From/Into traits
89// like Vec<u8> does. So here we are.
90
91impl From<Vec<u8>> for ByteString {
92  fn from(vec: Vec<u8>) -> Self {
93    ByteString(SmallVec::from_vec(vec))
94  }
95}
96
97#[allow(clippy::from_over_into)]
98impl Into<Vec<u8>> for ByteString {
99  fn into(self) -> Vec<u8> {
100    self.0.into_vec()
101  }
102}
103
104impl From<&[u8]> for ByteString {
105  fn from(s: &[u8]) -> Self {
106    ByteString(SmallVec::from_slice(s))
107  }
108}
109
110impl From<&str> for ByteString {
111  fn from(s: &str) -> Self {
112    let v: Vec<u8> = s.into();
113    ByteString::from(v)
114  }
115}
116
117impl From<String> for ByteString {
118  fn from(s: String) -> Self {
119    ByteString::from(s.into_bytes())
120  }
121}