1use crate::Isolate;
2use crate::Local;
3use crate::String;
4use crate::binding::v8__String__kMaxLength;
5use crate::isolate::RealIsolate;
6use crate::scope::PinScope;
7use crate::support::Opaque;
8use crate::support::char;
9use crate::support::int;
10use crate::support::size_t;
11use std::borrow::Cow;
12use std::convert::TryInto;
13use std::default::Default;
14use std::ffi::c_void;
15use std::marker::PhantomData;
16use std::mem::MaybeUninit;
17use std::ptr::NonNull;
18use std::slice;
19
20unsafe extern "C" {
21 fn v8__String__Empty(isolate: *mut RealIsolate) -> *const String;
22
23 fn v8__String__NewFromUtf8(
24 isolate: *mut RealIsolate,
25 data: *const char,
26 new_type: NewStringType,
27 length: int,
28 ) -> *const String;
29
30 fn v8__String__NewFromOneByte(
31 isolate: *mut RealIsolate,
32 data: *const u8,
33 new_type: NewStringType,
34 length: int,
35 ) -> *const String;
36
37 fn v8__String__NewFromTwoByte(
38 isolate: *mut RealIsolate,
39 data: *const u16,
40 new_type: NewStringType,
41 length: int,
42 ) -> *const String;
43
44 fn v8__String__Length(this: *const String) -> int;
45
46 fn v8__String__Utf8Length(
47 this: *const String,
48 isolate: *mut RealIsolate,
49 ) -> int;
50
51 fn v8__String__Write_v2(
52 this: *const String,
53 isolate: *mut RealIsolate,
54 offset: u32,
55 length: u32,
56 buffer: *mut u16,
57 flags: int,
58 );
59
60 fn v8__String__WriteOneByte_v2(
61 this: *const String,
62 isolate: *mut RealIsolate,
63 offset: u32,
64 length: u32,
65 buffer: *mut u8,
66 flags: int,
67 );
68
69 fn v8__String__WriteUtf8_v2(
70 this: *const String,
71 isolate: *mut RealIsolate,
72 buffer: *mut char,
73 capacity: size_t,
74 flags: int,
75 processed_characters_return: *mut size_t,
76 ) -> int;
77
78 fn v8__String__GetExternalStringResource(
79 this: *const String,
80 ) -> *mut ExternalStringResource;
81 fn v8__String__GetExternalStringResourceBase(
82 this: *const String,
83 encoding: *mut Encoding,
84 ) -> *mut ExternalStringResourceBase;
85
86 fn v8__String__NewExternalOneByteConst(
87 isolate: *mut RealIsolate,
88 onebyte_const: *const OneByteConst,
89 ) -> *const String;
90
91 fn v8__String__NewExternalOneByteStatic(
92 isolate: *mut RealIsolate,
93 buffer: *const char,
94 length: int,
95 ) -> *const String;
96
97 fn v8__String__NewExternalOneByte(
98 isolate: *mut RealIsolate,
99 buffer: *mut char,
100 length: size_t,
101 free: unsafe extern "C" fn(*mut char, size_t),
102 ) -> *const String;
103
104 fn v8__String__NewExternalTwoByteStatic(
105 isolate: *mut RealIsolate,
106 buffer: *const u16,
107 length: int,
108 ) -> *const String;
109
110 #[allow(dead_code)]
111 fn v8__String__IsExternal(this: *const String) -> bool;
112 fn v8__String__IsExternalOneByte(this: *const String) -> bool;
113 fn v8__String__IsExternalTwoByte(this: *const String) -> bool;
114 #[allow(dead_code)]
115 fn v8__String__IsOneByte(this: *const String) -> bool;
116 fn v8__String__ContainsOnlyOneByte(this: *const String) -> bool;
117 fn v8__ExternalOneByteStringResource__data(
118 this: *const ExternalOneByteStringResource,
119 ) -> *const char;
120 fn v8__ExternalOneByteStringResource__length(
121 this: *const ExternalOneByteStringResource,
122 ) -> size_t;
123
124 fn v8__String__ValueView__CONSTRUCT(
125 buf: *mut ValueView,
126 isolate: *mut RealIsolate,
127 string: *const String,
128 );
129 fn v8__String__ValueView__DESTRUCT(this: *mut ValueView);
130 fn v8__String__ValueView__is_one_byte(this: *const ValueView) -> bool;
131 fn v8__String__ValueView__data(this: *const ValueView) -> *const c_void;
132 fn v8__String__ValueView__length(this: *const ValueView) -> int;
133}
134
135#[derive(PartialEq, Debug)]
136#[repr(C)]
137pub enum Encoding {
138 Unknown = 0x1,
139 TwoByte = 0x2,
140 OneByte = 0x8,
141}
142
143#[repr(C)]
144pub struct ExternalStringResource(Opaque);
145
146#[repr(C)]
147pub struct ExternalStringResourceBase(Opaque);
148
149#[repr(C)]
150pub struct ExternalOneByteStringResource(Opaque);
157
158impl ExternalOneByteStringResource {
159 #[inline]
163 pub fn data(&self) -> *const char {
164 unsafe { v8__ExternalOneByteStringResource__data(self) }
165 }
166
167 #[inline]
169 pub fn length(&self) -> usize {
170 unsafe { v8__ExternalOneByteStringResource__length(self) }
171 }
172
173 #[inline]
176 pub fn as_bytes(&self) -> &[u8] {
177 let len = self.length();
178 if len == 0 {
179 &[]
180 } else {
181 unsafe { std::slice::from_raw_parts(self.data().cast(), len) }
183 }
184 }
185}
186
187#[repr(C)]
189#[derive(Copy, Clone, Debug)]
190pub struct OneByteConst {
191 vtable: *const OneByteConstNoOp,
192 cached_data: *const char,
193 length: usize,
194}
195
196impl OneByteConst {
197 #[inline(always)]
199 pub const fn as_str(&self) -> &str {
200 if self.length == 0 {
201 ""
202 } else {
203 unsafe {
205 std::str::from_utf8_unchecked(std::slice::from_raw_parts(
206 self.cached_data as _,
207 self.length,
208 ))
209 }
210 }
211 }
212}
213
214impl AsRef<str> for OneByteConst {
215 #[inline(always)]
216 fn as_ref(&self) -> &str {
217 self.as_str()
218 }
219}
220
221impl AsRef<[u8]> for OneByteConst {
222 #[inline(always)]
223 fn as_ref(&self) -> &[u8] {
224 self.as_str().as_bytes()
225 }
226}
227
228impl std::ops::Deref for OneByteConst {
229 type Target = str;
230 #[inline(always)]
231 fn deref(&self) -> &Self::Target {
232 self.as_ref()
233 }
234}
235
236unsafe impl Sync for OneByteConst {}
243
244unsafe extern "C" fn one_byte_const_no_op(_this: *const OneByteConst) {}
245unsafe extern "C" fn one_byte_const_is_cacheable(
246 _this: *const OneByteConst,
247) -> bool {
248 true
249}
250unsafe extern "C" fn one_byte_const_data(
251 this: *const OneByteConst,
252) -> *const char {
253 unsafe { (*this).cached_data }
255}
256unsafe extern "C" fn one_byte_const_length(this: *const OneByteConst) -> usize {
257 unsafe { (*this).length }
259}
260unsafe extern "C" fn one_byte_const_unaccount(
261 _this: *const OneByteConst,
262 _isolate: *mut RealIsolate,
263) {
264}
265unsafe extern "C" fn one_byte_const_estimate_memory_usage(
266 _this: *const OneByteConst,
267) -> size_t {
268 usize::MAX }
270unsafe extern "C" fn one_byte_const_estimate_shared_memory_usage(
271 _this: *const OneByteConst,
272 _recorder: *mut (),
273) {
274}
275
276type OneByteConstNoOp = unsafe extern "C" fn(*const OneByteConst);
277type OneByteConstIsCacheable =
278 unsafe extern "C" fn(*const OneByteConst) -> bool;
279type OneByteConstData =
280 unsafe extern "C" fn(*const OneByteConst) -> *const char;
281type OneByteConstLength = unsafe extern "C" fn(*const OneByteConst) -> usize;
282type OneByteConstUnaccount =
283 unsafe extern "C" fn(*const OneByteConst, *mut RealIsolate);
284type OneByteConstEstimateMemoryUsage =
285 unsafe extern "C" fn(*const OneByteConst) -> size_t;
286type OneByteConstEstimateSharedMemoryUsage =
287 unsafe extern "C" fn(*const OneByteConst, *mut ());
288
289#[repr(C)]
290struct OneByteConstVtable {
291 #[cfg(target_family = "windows")]
292 _offset_to_top: usize,
297 _typeinfo: *const (),
303 delete1: OneByteConstNoOp,
310 #[cfg(not(target_family = "windows"))]
314 delete2: OneByteConstNoOp,
315 is_cacheable: OneByteConstIsCacheable,
316 unaccount: OneByteConstUnaccount,
317 estimate_memory_usage: OneByteConstEstimateMemoryUsage,
318 estimate_shared_memory_usage: OneByteConstEstimateSharedMemoryUsage,
319 dispose: OneByteConstNoOp,
320 lock: OneByteConstNoOp,
321 unlock: OneByteConstNoOp,
322 data: OneByteConstData,
323 length: OneByteConstLength,
324}
325
326const ONE_BYTE_CONST_VTABLE: OneByteConstVtable = OneByteConstVtable {
327 #[cfg(target_family = "windows")]
328 _offset_to_top: 0,
329 _typeinfo: std::ptr::null(),
330 delete1: one_byte_const_no_op,
331 #[cfg(not(target_family = "windows"))]
332 delete2: one_byte_const_no_op,
333 is_cacheable: one_byte_const_is_cacheable,
334 unaccount: one_byte_const_unaccount,
335 estimate_memory_usage: one_byte_const_estimate_memory_usage,
336 estimate_shared_memory_usage: one_byte_const_estimate_shared_memory_usage,
337 dispose: one_byte_const_no_op,
338 lock: one_byte_const_no_op,
339 unlock: one_byte_const_no_op,
340 data: one_byte_const_data,
341 length: one_byte_const_length,
342};
343
344#[repr(C)]
345#[derive(Debug, Default)]
346pub enum NewStringType {
347 #[default]
348 Normal,
349 Internalized,
350}
351
352bitflags! {
353 #[derive(Clone, Copy, Default)]
354 #[repr(transparent)]
355 pub struct WriteOptions: int {
356 const NO_OPTIONS = 0;
357 const HINT_MANY_WRITES_EXPECTED = 1;
358 const NO_NULL_TERMINATION = 2;
359 const PRESERVE_ONE_BYTE_NULL = 4;
360 const REPLACE_INVALID_UTF8 = 8;
364 }
365}
366
367bitflags! {
368 #[derive(Clone, Copy, Default)]
369 #[repr(transparent)]
370 pub struct WriteFlags: int {
371 const kNullTerminate = crate::binding::v8_String_WriteFlags_kNullTerminate as _;
372 const kReplaceInvalidUtf8 = crate::binding::v8_String_WriteFlags_kReplaceInvalidUtf8 as _;
373 }
374}
375
376impl String {
377 pub const MAX_LENGTH: usize = v8__String__kMaxLength as _;
381
382 #[inline(always)]
383 pub fn empty<'s>(scope: &PinScope<'s, '_, ()>) -> Local<'s, String> {
384 unsafe { scope.cast_local(|sd| v8__String__Empty(sd.get_isolate_ptr())) }
387 .unwrap()
388 }
389
390 #[inline(always)]
393 pub fn new_from_utf8<'s>(
394 scope: &PinScope<'s, '_, ()>,
395 buffer: &[u8],
396 new_type: NewStringType,
397 ) -> Option<Local<'s, String>> {
398 if buffer.is_empty() {
399 return Some(Self::empty(scope));
400 }
401 let buffer_len = buffer.len().try_into().ok()?;
402 unsafe {
403 scope.cast_local(|sd| {
404 v8__String__NewFromUtf8(
405 sd.get_isolate_ptr(),
406 buffer.as_ptr() as *const char,
407 new_type,
408 buffer_len,
409 )
410 })
411 }
412 }
413
414 #[inline(always)]
417 pub fn new_from_one_byte<'s>(
418 scope: &PinScope<'s, '_, ()>,
419 buffer: &[u8],
420 new_type: NewStringType,
421 ) -> Option<Local<'s, String>> {
422 let buffer_len = buffer.len().try_into().ok()?;
423 unsafe {
424 scope.cast_local(|sd| {
425 v8__String__NewFromOneByte(
426 sd.get_isolate_ptr(),
427 buffer.as_ptr(),
428 new_type,
429 buffer_len,
430 )
431 })
432 }
433 }
434
435 #[inline(always)]
438 pub fn new_from_two_byte<'s>(
439 scope: &PinScope<'s, '_, ()>,
440 buffer: &[u16],
441 new_type: NewStringType,
442 ) -> Option<Local<'s, String>> {
443 let buffer_len = buffer.len().try_into().ok()?;
444 unsafe {
445 scope.cast_local(|sd| {
446 v8__String__NewFromTwoByte(
447 sd.get_isolate_ptr(),
448 buffer.as_ptr(),
449 new_type,
450 buffer_len,
451 )
452 })
453 }
454 }
455
456 #[inline(always)]
458 pub fn length(&self) -> usize {
459 unsafe { v8__String__Length(self) as usize }
460 }
461
462 #[inline(always)]
465 pub fn utf8_length(&self, scope: &Isolate) -> usize {
466 unsafe { v8__String__Utf8Length(self, scope.as_real_ptr()) as usize }
467 }
468
469 #[inline(always)]
472 pub fn write_v2(
473 &self,
474 scope: &Isolate,
475 offset: u32,
476 buffer: &mut [u16],
477 flags: WriteFlags,
478 ) {
479 unsafe {
480 v8__String__Write_v2(
481 self,
482 scope.as_real_ptr(),
483 offset,
484 self.length().min(buffer.len()) as _,
485 buffer.as_mut_ptr(),
486 flags.bits(),
487 )
488 }
489 }
490
491 #[inline(always)]
494 pub fn write_one_byte_v2(
495 &self,
496 scope: &Isolate,
497 offset: u32,
498 buffer: &mut [u8],
499 flags: WriteFlags,
500 ) {
501 unsafe {
502 v8__String__WriteOneByte_v2(
503 self,
504 scope.as_real_ptr(),
505 offset,
506 self.length().min(buffer.len()) as _,
507 buffer.as_mut_ptr(),
508 flags.bits(),
509 )
510 }
511 }
512
513 #[inline(always)]
516 pub fn write_one_byte_uninit_v2(
517 &self,
518 scope: &Isolate,
519 offset: u32,
520 buffer: &mut [MaybeUninit<u8>],
521 flags: WriteFlags,
522 ) {
523 unsafe {
524 v8__String__WriteOneByte_v2(
525 self,
526 scope.as_real_ptr(),
527 offset,
528 self.length().min(buffer.len()) as _,
529 buffer.as_mut_ptr() as _,
530 flags.bits(),
531 )
532 }
533 }
534
535 #[inline(always)]
537 pub fn write_utf8_v2(
538 &self,
539 scope: &Isolate,
540 buffer: &mut [u8],
541 flags: WriteFlags,
542 processed_characters_return: Option<&mut usize>,
543 ) -> usize {
544 unsafe {
545 let buffer = {
550 let len = buffer.len();
551 let data = buffer.as_mut_ptr().cast();
552 slice::from_raw_parts_mut(data, len)
553 };
554 self.write_utf8_uninit_v2(
555 scope,
556 buffer,
557 flags,
558 processed_characters_return,
559 )
560 }
561 }
562
563 pub fn write_utf8_uninit_v2(
565 &self,
566 scope: &Isolate,
567 buffer: &mut [MaybeUninit<u8>],
568 flags: WriteFlags,
569 processed_characters_return: Option<&mut usize>,
570 ) -> usize {
571 let bytes = unsafe {
572 v8__String__WriteUtf8_v2(
573 self,
574 scope.as_real_ptr(),
575 buffer.as_mut_ptr() as _,
576 buffer.len(),
577 flags.bits(),
578 processed_characters_return
579 .map(|p| p as *mut _)
580 .unwrap_or(std::ptr::null_mut()),
581 )
582 };
583 bytes as usize
584 }
585
586 #[inline(always)]
588 pub fn new<'s>(
589 scope: &PinScope<'s, '_, ()>,
590 value: &str,
591 ) -> Option<Local<'s, String>> {
592 Self::new_from_utf8(scope, value.as_ref(), NewStringType::Normal)
593 }
594
595 #[inline(always)]
598 pub const fn create_external_onebyte_const(
599 buffer: &'static [u8],
600 ) -> OneByteConst {
601 assert!(buffer.is_ascii() && buffer.len() <= ((1 << 29) - 24));
604 OneByteConst {
605 vtable: &ONE_BYTE_CONST_VTABLE.delete1,
606 cached_data: buffer.as_ptr() as *const char,
607 length: buffer.len(),
608 }
609 }
610
611 #[inline(always)]
620 pub const unsafe fn create_external_onebyte_const_unchecked(
621 buffer: &'static [u8],
622 ) -> OneByteConst {
623 OneByteConst {
624 vtable: &ONE_BYTE_CONST_VTABLE.delete1,
625 cached_data: buffer.as_ptr() as *const char,
626 length: buffer.len(),
627 }
628 }
629
630 #[inline(always)]
636 pub fn new_from_onebyte_const<'s>(
637 scope: &PinScope<'s, '_, ()>,
638 onebyte_const: &'static OneByteConst,
639 ) -> Option<Local<'s, String>> {
640 unsafe {
641 scope.cast_local(|sd| {
642 v8__String__NewExternalOneByteConst(sd.get_isolate_ptr(), onebyte_const)
643 })
644 }
645 }
646
647 #[inline(always)]
650 pub fn new_external_onebyte_static<'s>(
651 scope: &PinScope<'s, '_, ()>,
652 buffer: &'static [u8],
653 ) -> Option<Local<'s, String>> {
654 let buffer_len = buffer.len().try_into().ok()?;
655 unsafe {
656 scope.cast_local(|sd| {
657 v8__String__NewExternalOneByteStatic(
658 sd.get_isolate_ptr(),
659 buffer.as_ptr() as *const char,
660 buffer_len,
661 )
662 })
663 }
664 }
665
666 #[inline(always)]
670 pub fn new_external_onebyte<'s>(
671 scope: &PinScope<'s, '_, ()>,
672 buffer: Box<[u8]>,
673 ) -> Option<Local<'s, String>> {
674 let buffer_len = buffer.len();
675 unsafe {
676 scope.cast_local(|sd| {
677 v8__String__NewExternalOneByte(
678 sd.get_isolate_ptr(),
679 Box::into_raw(buffer).cast::<char>(),
680 buffer_len,
681 free_rust_external_onebyte,
682 )
683 })
684 }
685 }
686
687 #[inline(always)]
695 pub unsafe fn new_external_onebyte_raw<'s>(
696 scope: &PinScope<'s, '_, ()>,
697 buffer: *mut char,
698 buffer_len: usize,
699 destructor: unsafe extern "C" fn(*mut char, usize),
700 ) -> Option<Local<'s, String>> {
701 unsafe {
702 scope.cast_local(|sd| {
703 v8__String__NewExternalOneByte(
704 sd.get_isolate_ptr(),
705 buffer,
706 buffer_len,
707 destructor,
708 )
709 })
710 }
711 }
712
713 #[inline(always)]
715 pub fn new_external_twobyte_static<'s>(
716 scope: &PinScope<'s, '_, ()>,
717 buffer: &'static [u16],
718 ) -> Option<Local<'s, String>> {
719 let buffer_len = buffer.len().try_into().ok()?;
720 unsafe {
721 scope.cast_local(|sd| {
722 v8__String__NewExternalTwoByteStatic(
723 sd.get_isolate_ptr(),
724 buffer.as_ptr(),
725 buffer_len,
726 )
727 })
728 }
729 }
730
731 #[inline]
735 pub fn get_external_string_resource(
736 &self,
737 ) -> Option<NonNull<ExternalStringResource>> {
738 NonNull::new(unsafe { v8__String__GetExternalStringResource(self) })
739 }
740
741 #[inline]
745 pub fn get_external_onebyte_string_resource(
746 &self,
747 ) -> Option<NonNull<ExternalOneByteStringResource>> {
748 let (base, encoding) = self.get_external_string_resource_base();
749 let base = base?;
750 if encoding != Encoding::OneByte {
751 return None;
752 }
753
754 Some(base.cast())
755 }
756
757 pub fn get_external_string_resource_base(
762 &self,
763 ) -> (Option<NonNull<ExternalStringResourceBase>>, Encoding) {
764 let mut encoding = Encoding::Unknown;
765 (
766 NonNull::new(unsafe {
767 v8__String__GetExternalStringResourceBase(self, &mut encoding)
768 }),
769 encoding,
770 )
771 }
772
773 #[inline(always)]
775 pub fn is_external(&self) -> bool {
776 self.is_external_onebyte() || self.is_external_twobyte()
783 }
784
785 #[inline(always)]
788 pub fn is_external_onebyte(&self) -> bool {
789 unsafe { v8__String__IsExternalOneByte(self) }
790 }
791
792 #[inline(always)]
795 pub fn is_external_twobyte(&self) -> bool {
796 unsafe { v8__String__IsExternalTwoByte(self) }
797 }
798
799 #[inline(always)]
808 pub fn is_onebyte(&self) -> bool {
809 unsafe { v8__String__IsOneByte(self) }
810 }
811
812 #[inline(always)]
815 pub fn contains_only_onebyte(&self) -> bool {
816 unsafe { v8__String__ContainsOnlyOneByte(self) }
817 }
818
819 pub fn to_rust_string_lossy(&self, scope: &Isolate) -> std::string::String {
822 let len_utf16 = self.length();
823
824 if len_utf16 == 0 {
826 return std::string::String::new();
827 }
828
829 let len_utf8 = self.utf8_length(scope);
830
831 if self.is_onebyte() && len_utf8 == len_utf16 {
834 unsafe {
835 let layout = std::alloc::Layout::from_size_align(len_utf16, 1).unwrap();
838 let data = std::alloc::alloc(layout) as *mut MaybeUninit<u8>;
839 let buffer = std::ptr::slice_from_raw_parts_mut(data, len_utf16);
840
841 self.write_one_byte_uninit_v2(
843 scope,
844 0,
845 &mut *buffer,
846 WriteFlags::kReplaceInvalidUtf8,
847 );
848
849 let buffer = data as *mut u8;
851 return std::string::String::from_raw_parts(
852 buffer, len_utf16, len_utf16,
853 );
854 }
855 }
856
857 unsafe {
860 let layout = std::alloc::Layout::from_size_align(len_utf8, 1).unwrap();
863 let data = std::alloc::alloc(layout) as *mut MaybeUninit<u8>;
864 let buffer = std::ptr::slice_from_raw_parts_mut(data, len_utf8);
865
866 let length = self.write_utf8_uninit_v2(
868 scope,
869 &mut *buffer,
870 WriteFlags::kReplaceInvalidUtf8,
871 None,
872 );
873 debug_assert!(length == len_utf8);
874
875 let buffer = data as *mut u8;
877 std::string::String::from_raw_parts(buffer, length, len_utf8)
878 }
879 }
880
881 pub fn to_rust_cow_lossy<'a, const N: usize>(
884 &self,
885 scope: &mut Isolate,
886 buffer: &'a mut [MaybeUninit<u8>; N],
887 ) -> Cow<'a, str> {
888 let len_utf16 = self.length();
889
890 if len_utf16 == 0 {
892 return "".into();
893 }
894
895 let len_utf8 = self.utf8_length(scope);
897
898 if self.is_onebyte() && len_utf8 == len_utf16 {
901 if len_utf16 <= N {
902 self.write_one_byte_uninit_v2(scope, 0, buffer, WriteFlags::empty());
903 unsafe {
904 let buffer = &mut buffer[..len_utf16];
906 let buffer = &mut *(buffer as *mut [_] as *mut [u8]);
907
908 return Cow::Borrowed(std::str::from_utf8_unchecked(buffer));
910 }
911 }
912
913 unsafe {
914 let layout = std::alloc::Layout::from_size_align(len_utf16, 1).unwrap();
917 let data = std::alloc::alloc(layout) as *mut MaybeUninit<u8>;
918 let buffer = std::ptr::slice_from_raw_parts_mut(data, len_utf16);
919
920 self.write_one_byte_uninit_v2(
922 scope,
923 0,
924 &mut *buffer,
925 WriteFlags::kReplaceInvalidUtf8,
926 );
927
928 let buffer = data as *mut u8;
930 return Cow::Owned(std::string::String::from_raw_parts(
931 buffer, len_utf16, len_utf16,
932 ));
933 }
934 }
935
936 if len_utf8 <= N {
937 let length = self.write_utf8_uninit_v2(
939 scope,
940 buffer,
941 WriteFlags::kReplaceInvalidUtf8,
942 None,
943 );
944 debug_assert!(length == len_utf8);
945
946 unsafe {
948 let buffer = &mut buffer[..length];
950 let buffer = &mut *(buffer as *mut [_] as *mut [u8]);
951
952 return Cow::Borrowed(std::str::from_utf8_unchecked(buffer));
954 }
955 }
956
957 unsafe {
960 let layout = std::alloc::Layout::from_size_align(len_utf8, 1).unwrap();
963 let data = std::alloc::alloc(layout) as *mut MaybeUninit<u8>;
964 let buffer = std::ptr::slice_from_raw_parts_mut(data, len_utf8);
965
966 let length = self.write_utf8_uninit_v2(
968 scope,
969 &mut *buffer,
970 WriteFlags::kReplaceInvalidUtf8,
971 None,
972 );
973 debug_assert!(length == len_utf8);
974
975 let buffer = data as *mut u8;
977 Cow::Owned(std::string::String::from_raw_parts(
978 buffer, length, len_utf8,
979 ))
980 }
981 }
982}
983
984#[inline]
985pub unsafe extern "C" fn free_rust_external_onebyte(s: *mut char, len: usize) {
986 unsafe {
987 let slice = std::slice::from_raw_parts_mut(s, len);
988
989 drop(Box::from_raw(slice));
991 }
992}
993
994#[derive(Debug, PartialEq)]
995pub enum ValueViewData<'s> {
996 OneByte(&'s [u8]),
997 TwoByte(&'s [u16]),
998}
999
1000#[repr(C)]
1009pub struct ValueView<'s>(
1010 [u8; crate::binding::v8__String__ValueView_SIZE],
1011 PhantomData<&'s ()>,
1012);
1013
1014impl<'s> ValueView<'s> {
1015 #[inline(always)]
1016 pub fn new(isolate: &mut Isolate, string: Local<'s, String>) -> Self {
1017 let mut v = std::mem::MaybeUninit::uninit();
1018 unsafe {
1019 v8__String__ValueView__CONSTRUCT(
1020 v.as_mut_ptr(),
1021 isolate.as_real_ptr(),
1022 &*string,
1023 );
1024 v.assume_init()
1025 }
1026 }
1027
1028 #[inline(always)]
1029 pub fn data(&self) -> ValueViewData<'_> {
1030 unsafe {
1031 let data = v8__String__ValueView__data(self);
1032 let length = v8__String__ValueView__length(self) as usize;
1033 if v8__String__ValueView__is_one_byte(self) {
1034 ValueViewData::OneByte(std::slice::from_raw_parts(data as _, length))
1035 } else {
1036 ValueViewData::TwoByte(std::slice::from_raw_parts(data as _, length))
1037 }
1038 }
1039 }
1040}
1041
1042impl Drop for ValueView<'_> {
1043 fn drop(&mut self) {
1044 unsafe { v8__String__ValueView__DESTRUCT(self) }
1045 }
1046}