Coverage Report

Created: 2023-04-25 07:07

/rust/registry/src/index.crates.io-6f17d22bba15001f/v8-0.44.3/src/string.rs
Line
Count
Source (jump to first uncovered line)
1
use std::convert::TryInto;
2
use std::default::Default;
3
use std::mem::forget;
4
use std::slice;
5
6
use crate::support::char;
7
use crate::support::int;
8
use crate::HandleScope;
9
use crate::Isolate;
10
use crate::Local;
11
use crate::String;
12
13
extern "C" {
14
  fn v8__String__kMaxLength() -> libc::size_t;
15
16
  fn v8__String__Empty(isolate: *mut Isolate) -> *const String;
17
18
  fn v8__String__NewFromUtf8(
19
    isolate: *mut Isolate,
20
    data: *const char,
21
    new_type: NewStringType,
22
    length: int,
23
  ) -> *const String;
24
25
  fn v8__String__NewFromOneByte(
26
    isolate: *mut Isolate,
27
    data: *const u8,
28
    new_type: NewStringType,
29
    length: int,
30
  ) -> *const String;
31
32
  fn v8__String__NewFromTwoByte(
33
    isolate: *mut Isolate,
34
    data: *const u16,
35
    new_type: NewStringType,
36
    length: int,
37
  ) -> *const String;
38
39
  fn v8__String__Length(this: *const String) -> int;
40
41
  fn v8__String__Utf8Length(this: *const String, isolate: *mut Isolate) -> int;
42
43
  fn v8__String__Write(
44
    this: *const String,
45
    isolate: *mut Isolate,
46
    buffer: *mut u16,
47
    start: int,
48
    length: int,
49
    options: WriteOptions,
50
  ) -> int;
51
52
  fn v8__String__WriteOneByte(
53
    this: *const String,
54
    isolate: *mut Isolate,
55
    buffer: *mut u8,
56
    start: int,
57
    length: int,
58
    options: WriteOptions,
59
  ) -> int;
60
61
  fn v8__String__WriteUtf8(
62
    this: *const String,
63
    isolate: *mut Isolate,
64
    buffer: *mut char,
65
    length: int,
66
    nchars_ref: *mut int,
67
    options: WriteOptions,
68
  ) -> int;
69
70
  fn v8__String__NewExternalOneByteStatic(
71
    isolate: *mut Isolate,
72
    buffer: *const char,
73
    length: int,
74
  ) -> *const String;
75
76
  fn v8__String__NewExternalTwoByteStatic(
77
    isolate: *mut Isolate,
78
    buffer: *const u16,
79
    length: int,
80
  ) -> *const String;
81
82
  #[allow(dead_code)]
83
  fn v8__String__IsExternal(this: *const String) -> bool;
84
  fn v8__String__IsExternalOneByte(this: *const String) -> bool;
85
  fn v8__String__IsExternalTwoByte(this: *const String) -> bool;
86
  #[allow(dead_code)]
87
  fn v8__String__IsOneByte(this: *const String) -> bool;
88
  fn v8__String__ContainsOnlyOneByte(this: *const String) -> bool;
89
}
90
91
#[repr(C)]
92
0
#[derive(Debug)]
93
pub enum NewStringType {
94
  Normal,
95
  Internalized,
96
}
97
98
impl Default for NewStringType {
99
0
  fn default() -> Self {
100
0
    NewStringType::Normal
101
0
  }
102
}
103
104
bitflags! {
105
0
  #[derive(Default)]
106
  #[repr(transparent)]
107
  pub struct WriteOptions: int {
108
    const NO_OPTIONS = 0;
109
    const HINT_MANY_WRITES_EXPECTED = 1;
110
    const NO_NULL_TERMINATION = 2;
111
    const PRESERVE_ONE_BYTE_NULL = 4;
112
    // Used by WriteUtf8 to replace orphan surrogate code units with the
113
    // unicode replacement character. Needs to be set to guarantee valid UTF-8
114
    // output.
115
    const REPLACE_INVALID_UTF8 = 8;
116
  }
117
}
118
119
impl String {
120
  /// The maximum length (in bytes) of a buffer that a v8::String can be built
121
  /// from. Attempting to create a v8::String from a larger buffer will result
122
  /// in None being returned.
123
0
  pub fn max_length() -> usize {
124
0
    unsafe { v8__String__kMaxLength() }
125
0
  }
126
127
1.54k
  pub fn empty<'s>(scope: &mut HandleScope<'s, ()>) -> Local<'s, String> {
128
1.54k
    // FIXME(bnoordhuis) v8__String__Empty() is infallible so there
129
1.54k
    // is no need to box up the result, only to unwrap it again.
130
1.54k
    unsafe { scope.cast_local(|sd| v8__String__Empty(sd.get_isolate_ptr())) }
131
1.54k
      .unwrap()
132
1.54k
  }
133
134
  /// Allocates a new string from UTF-8 data. Only returns an empty value when
135
  /// length > kMaxLength
136
123k
  pub fn new_from_utf8<'s>(
137
123k
    scope: &mut HandleScope<'s, ()>,
138
123k
    buffer: &[u8],
139
123k
    new_type: NewStringType,
140
123k
  ) -> Option<Local<'s, String>> {
141
123k
    if buffer.is_empty() {
142
1.54k
      return Some(Self::empty(scope));
143
121k
    }
144
121k
    let buffer_len = buffer.len().try_into().ok()?;
145
    unsafe {
146
121k
      scope.cast_local(|sd| {
147
121k
        v8__String__NewFromUtf8(
148
121k
          sd.get_isolate_ptr(),
149
121k
          buffer.as_ptr() as *const char,
150
121k
          new_type,
151
121k
          buffer_len,
152
121k
        )
153
121k
      })
154
    }
155
123k
  }
156
157
  /// Allocates a new string from Latin-1 data.  Only returns an empty value when
158
  /// length > kMaxLength.
159
0
  pub fn new_from_one_byte<'s>(
160
0
    scope: &mut HandleScope<'s, ()>,
161
0
    buffer: &[u8],
162
0
    new_type: NewStringType,
163
0
  ) -> Option<Local<'s, String>> {
164
0
    let buffer_len = buffer.len().try_into().ok()?;
165
    unsafe {
166
0
      scope.cast_local(|sd| {
167
0
        v8__String__NewFromOneByte(
168
0
          sd.get_isolate_ptr(),
169
0
          buffer.as_ptr(),
170
0
          new_type,
171
0
          buffer_len,
172
0
        )
173
0
      })
174
    }
175
0
  }
176
177
  /// Allocates a new string from UTF-16 data. Only returns an empty value when
178
  /// length > kMaxLength.
179
0
  pub fn new_from_two_byte<'s>(
180
0
    scope: &mut HandleScope<'s, ()>,
181
0
    buffer: &[u16],
182
0
    new_type: NewStringType,
183
0
  ) -> Option<Local<'s, String>> {
184
0
    let buffer_len = buffer.len().try_into().ok()?;
185
    unsafe {
186
0
      scope.cast_local(|sd| {
187
0
        v8__String__NewFromTwoByte(
188
0
          sd.get_isolate_ptr(),
189
0
          buffer.as_ptr(),
190
0
          new_type,
191
0
          buffer_len,
192
0
        )
193
0
      })
194
    }
195
0
  }
196
197
  /// Returns the number of characters (UTF-16 code units) in this string.
198
0
  pub fn length(&self) -> usize {
199
0
    unsafe { v8__String__Length(self) as usize }
200
0
  }
201
202
  /// Returns the number of bytes in the UTF-8 encoded representation of this
203
  /// string.
204
1.65k
  pub fn utf8_length(&self, scope: &mut Isolate) -> usize {
205
1.65k
    unsafe { v8__String__Utf8Length(self, scope) as usize }
206
1.65k
  }
207
208
  /// Writes the contents of the string to an external buffer, as 16-bit
209
  /// (UTF-16) character codes.
210
0
  pub fn write(
211
0
    &self,
212
0
    scope: &mut Isolate,
213
0
    buffer: &mut [u16],
214
0
    start: usize,
215
0
    options: WriteOptions,
216
0
  ) -> usize {
217
0
    unsafe {
218
0
      v8__String__Write(
219
0
        self,
220
0
        scope,
221
0
        buffer.as_mut_ptr(),
222
0
        start.try_into().unwrap_or(int::max_value()),
223
0
        buffer.len().try_into().unwrap_or(int::max_value()),
224
0
        options,
225
0
      ) as usize
226
0
    }
227
0
  }
228
229
  /// Writes the contents of the string to an external buffer, as one-byte
230
  /// (Latin-1) characters.
231
0
  pub fn write_one_byte(
232
0
    &self,
233
0
    scope: &mut Isolate,
234
0
    buffer: &mut [u8],
235
0
    start: usize,
236
0
    options: WriteOptions,
237
0
  ) -> usize {
238
0
    unsafe {
239
0
      v8__String__WriteOneByte(
240
0
        self,
241
0
        scope,
242
0
        buffer.as_mut_ptr(),
243
0
        start.try_into().unwrap_or(int::max_value()),
244
0
        buffer.len().try_into().unwrap_or(int::max_value()),
245
0
        options,
246
0
      ) as usize
247
0
    }
248
0
  }
249
250
  /// Writes the contents of the string to an external buffer, as UTF-8.
251
1.65k
  pub fn write_utf8(
252
1.65k
    &self,
253
1.65k
    scope: &mut Isolate,
254
1.65k
    buffer: &mut [u8],
255
1.65k
    nchars_ref: Option<&mut usize>,
256
1.65k
    options: WriteOptions,
257
1.65k
  ) -> usize {
258
1.65k
    let mut nchars_ref_int: int = 0;
259
1.65k
    let bytes = unsafe {
260
1.65k
      v8__String__WriteUtf8(
261
1.65k
        self,
262
1.65k
        scope,
263
1.65k
        buffer.as_mut_ptr() as *mut char,
264
1.65k
        buffer.len().try_into().unwrap_or(int::max_value()),
265
1.65k
        &mut nchars_ref_int,
266
1.65k
        options,
267
1.65k
      )
268
    };
269
1.65k
    if let Some(r) = nchars_ref {
270
0
      *r = nchars_ref_int as usize;
271
1.65k
    }
272
1.65k
    bytes as usize
273
1.65k
  }
274
275
  // Convenience function not present in the original V8 API.
276
123k
  pub fn new<'s>(
277
123k
    scope: &mut HandleScope<'s, ()>,
278
123k
    value: &str,
279
123k
  ) -> Option<Local<'s, String>> {
280
123k
    Self::new_from_utf8(scope, value.as_ref(), NewStringType::Normal)
281
123k
  }
282
283
  // Creates a v8::String from a `&'static [u8]`,
284
  // must be Latin-1 or ASCII, not UTF-8 !
285
0
  pub fn new_external_onebyte_static<'s>(
286
0
    scope: &mut HandleScope<'s, ()>,
287
0
    buffer: &'static [u8],
288
0
  ) -> Option<Local<'s, String>> {
289
0
    let buffer_len = buffer.len().try_into().ok()?;
290
    unsafe {
291
0
      scope.cast_local(|sd| {
292
0
        v8__String__NewExternalOneByteStatic(
293
0
          sd.get_isolate_ptr(),
294
0
          buffer.as_ptr() as *const char,
295
0
          buffer_len,
296
0
        )
297
0
      })
298
    }
299
0
  }
300
301
  // Creates a v8::String from a `&'static [u16]`.
302
0
  pub fn new_external_twobyte_static<'s>(
303
0
    scope: &mut HandleScope<'s, ()>,
304
0
    buffer: &'static [u16],
305
0
  ) -> Option<Local<'s, String>> {
306
0
    let buffer_len = buffer.len().try_into().ok()?;
307
    unsafe {
308
0
      scope.cast_local(|sd| {
309
0
        v8__String__NewExternalTwoByteStatic(
310
0
          sd.get_isolate_ptr(),
311
0
          buffer.as_ptr(),
312
0
          buffer_len,
313
0
        )
314
0
      })
315
    }
316
0
  }
317
318
  /// True if string is external
319
0
  pub fn is_external(&self) -> bool {
320
0
    // TODO: re-enable on next v8-release
321
0
    // Right now it fallbacks to Value::IsExternal, which is incorrect
322
0
    // See: https://source.chromium.org/chromium/_/chromium/v8/v8.git/+/1dd8624b524d14076160c1743f7da0b20fbe68e0
323
0
    // unsafe { v8__String__IsExternal(self) }
324
0
325
0
    // Fallback for now (though functionally identical)
326
0
    self.is_external_onebyte() || self.is_external_twobyte()
327
0
  }
328
329
  /// True if string is external & one-byte
330
  /// (e.g: created with new_external_onebyte_static)
331
0
  pub fn is_external_onebyte(&self) -> bool {
332
0
    unsafe { v8__String__IsExternalOneByte(self) }
333
0
  }
334
335
  /// True if string is external & two-byte
336
  /// (e.g: created with new_external_twobyte_static)
337
0
  pub fn is_external_twobyte(&self) -> bool {
338
0
    unsafe { v8__String__IsExternalTwoByte(self) }
339
0
  }
340
341
  /// True if string is known to contain only one-byte data.
342
  /// Doesn't read the string so can return false positives.
343
  ///
344
  /// For a method that will not return false positives at the cost of
345
  /// potentially reading the entire string, use [`contains_only_onebyte()`].
346
  ///
347
  /// [`contains_only_onebyte()`]: String::contains_only_onebyte
348
0
  pub fn is_onebyte(&self) -> bool {
349
0
    unsafe { v8__String__IsExternalOneByte(self) }
350
0
  }
351
352
  /// True if the string contains only one-byte data.
353
  /// Will read the entire string in some cases.
354
0
  pub fn contains_only_onebyte(&self) -> bool {
355
0
    unsafe { v8__String__ContainsOnlyOneByte(self) }
356
0
  }
357
358
  /// Convenience function not present in the original V8 API.
359
1.65k
  pub fn to_rust_string_lossy(
360
1.65k
    &self,
361
1.65k
    scope: &mut Isolate,
362
1.65k
  ) -> std::string::String {
363
1.65k
    let capacity = self.utf8_length(scope);
364
1.65k
    let mut string = std::string::String::with_capacity(capacity);
365
1.65k
    let data = string.as_mut_ptr();
366
1.65k
    forget(string);
367
1.65k
    let length = self.write_utf8(
368
1.65k
      scope,
369
1.65k
      unsafe { slice::from_raw_parts_mut(data, capacity) },
370
1.65k
      None,
371
1.65k
      WriteOptions::NO_NULL_TERMINATION | WriteOptions::REPLACE_INVALID_UTF8,
372
1.65k
    );
373
1.65k
    unsafe { std::string::String::from_raw_parts(data, length, capacity) }
374
1.65k
  }
375
}