/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 | | } |