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(
52 this: *const String,
53 isolate: *mut RealIsolate,
54 buffer: *mut u16,
55 start: int,
56 length: int,
57 options: WriteOptions,
58 ) -> int;
59
60 fn v8__String__Write_v2(
61 this: *const String,
62 isolate: *mut RealIsolate,
63 offset: u32,
64 length: u32,
65 buffer: *mut u16,
66 flags: int,
67 );
68
69 fn v8__String__WriteOneByte(
70 this: *const String,
71 isolate: *mut RealIsolate,
72 buffer: *mut u8,
73 start: int,
74 length: int,
75 options: WriteOptions,
76 ) -> int;
77
78 fn v8__String__WriteOneByte_v2(
79 this: *const String,
80 isolate: *mut RealIsolate,
81 offset: u32,
82 length: u32,
83 buffer: *mut u8,
84 flags: int,
85 );
86
87 fn v8__String__WriteUtf8(
88 this: *const String,
89 isolate: *mut RealIsolate,
90 buffer: *mut char,
91 length: int,
92 nchars_ref: *mut int,
93 options: WriteOptions,
94 ) -> int;
95
96 fn v8__String__WriteUtf8_v2(
97 this: *const String,
98 isolate: *mut RealIsolate,
99 buffer: *mut char,
100 capacity: size_t,
101 flags: int,
102 processed_characters_return: *mut size_t,
103 ) -> int;
104
105 fn v8__String__GetExternalStringResource(
106 this: *const String,
107 ) -> *mut ExternalStringResource;
108 fn v8__String__GetExternalStringResourceBase(
109 this: *const String,
110 encoding: *mut Encoding,
111 ) -> *mut ExternalStringResourceBase;
112
113 fn v8__String__NewExternalOneByteConst(
114 isolate: *mut RealIsolate,
115 onebyte_const: *const OneByteConst,
116 ) -> *const String;
117
118 fn v8__String__NewExternalOneByteStatic(
119 isolate: *mut RealIsolate,
120 buffer: *const char,
121 length: int,
122 ) -> *const String;
123
124 fn v8__String__NewExternalOneByte(
125 isolate: *mut RealIsolate,
126 buffer: *mut char,
127 length: size_t,
128 free: unsafe extern "C" fn(*mut char, size_t),
129 ) -> *const String;
130
131 fn v8__String__NewExternalTwoByteStatic(
132 isolate: *mut RealIsolate,
133 buffer: *const u16,
134 length: int,
135 ) -> *const String;
136
137 #[allow(dead_code)]
138 fn v8__String__IsExternal(this: *const String) -> bool;
139 fn v8__String__IsExternalOneByte(this: *const String) -> bool;
140 fn v8__String__IsExternalTwoByte(this: *const String) -> bool;
141 #[allow(dead_code)]
142 fn v8__String__IsOneByte(this: *const String) -> bool;
143 fn v8__String__ContainsOnlyOneByte(this: *const String) -> bool;
144 fn v8__ExternalOneByteStringResource__data(
145 this: *const ExternalOneByteStringResource,
146 ) -> *const char;
147 fn v8__ExternalOneByteStringResource__length(
148 this: *const ExternalOneByteStringResource,
149 ) -> size_t;
150
151 fn v8__String__ValueView__CONSTRUCT(
152 buf: *mut ValueView,
153 isolate: *mut RealIsolate,
154 string: *const String,
155 );
156 fn v8__String__ValueView__DESTRUCT(this: *mut ValueView);
157 fn v8__String__ValueView__is_one_byte(this: *const ValueView) -> bool;
158 fn v8__String__ValueView__data(this: *const ValueView) -> *const c_void;
159 fn v8__String__ValueView__length(this: *const ValueView) -> int;
160}
161
162#[derive(PartialEq, Debug)]
163#[repr(C)]
164pub enum Encoding {
165 Unknown = 0x1,
166 TwoByte = 0x2,
167 OneByte = 0x8,
168}
169
170#[repr(C)]
171pub struct ExternalStringResource(Opaque);
172
173#[repr(C)]
174pub struct ExternalStringResourceBase(Opaque);
175
176#[repr(C)]
177pub struct ExternalOneByteStringResource(Opaque);
184
185impl ExternalOneByteStringResource {
186 #[inline]
190 pub fn data(&self) -> *const char {
191 unsafe { v8__ExternalOneByteStringResource__data(self) }
192 }
193
194 #[inline]
196 pub fn length(&self) -> usize {
197 unsafe { v8__ExternalOneByteStringResource__length(self) }
198 }
199
200 #[inline]
203 pub fn as_bytes(&self) -> &[u8] {
204 let len = self.length();
205 if len == 0 {
206 &[]
207 } else {
208 unsafe { std::slice::from_raw_parts(self.data().cast(), len) }
210 }
211 }
212}
213
214#[repr(C)]
216#[derive(Copy, Clone, Debug)]
217pub struct OneByteConst {
218 vtable: *const OneByteConstNoOp,
219 cached_data: *const char,
220 length: usize,
221}
222
223impl OneByteConst {
224 #[inline(always)]
226 pub const fn as_str(&self) -> &str {
227 if self.length == 0 {
228 ""
229 } else {
230 unsafe {
232 std::str::from_utf8_unchecked(std::slice::from_raw_parts(
233 self.cached_data as _,
234 self.length,
235 ))
236 }
237 }
238 }
239}
240
241impl AsRef<str> for OneByteConst {
242 #[inline(always)]
243 fn as_ref(&self) -> &str {
244 self.as_str()
245 }
246}
247
248impl AsRef<[u8]> for OneByteConst {
249 #[inline(always)]
250 fn as_ref(&self) -> &[u8] {
251 self.as_str().as_bytes()
252 }
253}
254
255impl std::ops::Deref for OneByteConst {
256 type Target = str;
257 #[inline(always)]
258 fn deref(&self) -> &Self::Target {
259 self.as_ref()
260 }
261}
262
263unsafe impl Sync for OneByteConst {}
270
271unsafe extern "C" fn one_byte_const_no_op(_this: *const OneByteConst) {}
272unsafe extern "C" fn one_byte_const_is_cacheable(
273 _this: *const OneByteConst,
274) -> bool {
275 true
276}
277unsafe extern "C" fn one_byte_const_data(
278 this: *const OneByteConst,
279) -> *const char {
280 unsafe { (*this).cached_data }
282}
283unsafe extern "C" fn one_byte_const_length(this: *const OneByteConst) -> usize {
284 unsafe { (*this).length }
286}
287unsafe extern "C" fn one_byte_const_unaccount(
288 _this: *const OneByteConst,
289 _isolate: *mut RealIsolate,
290) {
291}
292unsafe extern "C" fn one_byte_const_estimate_memory_usage(
293 _this: *const OneByteConst,
294) -> size_t {
295 usize::MAX }
297unsafe extern "C" fn one_byte_const_estimate_shared_memory_usage(
298 _this: *const OneByteConst,
299 _recorder: *mut (),
300) {
301}
302
303type OneByteConstNoOp = unsafe extern "C" fn(*const OneByteConst);
304type OneByteConstIsCacheable =
305 unsafe extern "C" fn(*const OneByteConst) -> bool;
306type OneByteConstData =
307 unsafe extern "C" fn(*const OneByteConst) -> *const char;
308type OneByteConstLength = unsafe extern "C" fn(*const OneByteConst) -> usize;
309type OneByteConstUnaccount =
310 unsafe extern "C" fn(*const OneByteConst, *mut RealIsolate);
311type OneByteConstEstimateMemoryUsage =
312 unsafe extern "C" fn(*const OneByteConst) -> size_t;
313type OneByteConstEstimateSharedMemoryUsage =
314 unsafe extern "C" fn(*const OneByteConst, *mut ());
315
316#[repr(C)]
317struct OneByteConstVtable {
318 #[cfg(target_family = "windows")]
319 _offset_to_top: usize,
324 _typeinfo: *const (),
330 delete1: OneByteConstNoOp,
337 #[cfg(not(target_family = "windows"))]
341 delete2: OneByteConstNoOp,
342 is_cacheable: OneByteConstIsCacheable,
343 unaccount: OneByteConstUnaccount,
344 estimate_memory_usage: OneByteConstEstimateMemoryUsage,
345 estimate_shared_memory_usage: OneByteConstEstimateSharedMemoryUsage,
346 dispose: OneByteConstNoOp,
347 lock: OneByteConstNoOp,
348 unlock: OneByteConstNoOp,
349 data: OneByteConstData,
350 length: OneByteConstLength,
351}
352
353const ONE_BYTE_CONST_VTABLE: OneByteConstVtable = OneByteConstVtable {
354 #[cfg(target_family = "windows")]
355 _offset_to_top: 0,
356 _typeinfo: std::ptr::null(),
357 delete1: one_byte_const_no_op,
358 #[cfg(not(target_family = "windows"))]
359 delete2: one_byte_const_no_op,
360 is_cacheable: one_byte_const_is_cacheable,
361 unaccount: one_byte_const_unaccount,
362 estimate_memory_usage: one_byte_const_estimate_memory_usage,
363 estimate_shared_memory_usage: one_byte_const_estimate_shared_memory_usage,
364 dispose: one_byte_const_no_op,
365 lock: one_byte_const_no_op,
366 unlock: one_byte_const_no_op,
367 data: one_byte_const_data,
368 length: one_byte_const_length,
369};
370
371#[repr(C)]
372#[derive(Debug, Default)]
373pub enum NewStringType {
374 #[default]
375 Normal,
376 Internalized,
377}
378
379bitflags! {
380 #[derive(Clone, Copy, Default)]
381 #[repr(transparent)]
382 pub struct WriteOptions: int {
383 const NO_OPTIONS = 0;
384 const HINT_MANY_WRITES_EXPECTED = 1;
385 const NO_NULL_TERMINATION = 2;
386 const PRESERVE_ONE_BYTE_NULL = 4;
387 const REPLACE_INVALID_UTF8 = 8;
391 }
392}
393
394bitflags! {
395 #[derive(Clone, Copy, Default)]
396 #[repr(transparent)]
397 pub struct WriteFlags: int {
398 const kNullTerminate = crate::binding::v8_String_WriteFlags_kNullTerminate as _;
399 const kReplaceInvalidUtf8 = crate::binding::v8_String_WriteFlags_kReplaceInvalidUtf8 as _;
400 }
401}
402
403impl String {
404 pub const MAX_LENGTH: usize = v8__String__kMaxLength as _;
408
409 #[inline(always)]
410 pub fn empty<'s>(scope: &PinScope<'s, '_, ()>) -> Local<'s, String> {
411 unsafe { scope.cast_local(|sd| v8__String__Empty(sd.get_isolate_ptr())) }
414 .unwrap()
415 }
416
417 #[inline(always)]
420 pub fn new_from_utf8<'s>(
421 scope: &PinScope<'s, '_, ()>,
422 buffer: &[u8],
423 new_type: NewStringType,
424 ) -> Option<Local<'s, String>> {
425 if buffer.is_empty() {
426 return Some(Self::empty(scope));
427 }
428 let buffer_len = buffer.len().try_into().ok()?;
429 unsafe {
430 scope.cast_local(|sd| {
431 v8__String__NewFromUtf8(
432 sd.get_isolate_ptr(),
433 buffer.as_ptr() as *const char,
434 new_type,
435 buffer_len,
436 )
437 })
438 }
439 }
440
441 #[inline(always)]
444 pub fn new_from_one_byte<'s>(
445 scope: &PinScope<'s, '_, ()>,
446 buffer: &[u8],
447 new_type: NewStringType,
448 ) -> Option<Local<'s, String>> {
449 let buffer_len = buffer.len().try_into().ok()?;
450 unsafe {
451 scope.cast_local(|sd| {
452 v8__String__NewFromOneByte(
453 sd.get_isolate_ptr(),
454 buffer.as_ptr(),
455 new_type,
456 buffer_len,
457 )
458 })
459 }
460 }
461
462 #[inline(always)]
465 pub fn new_from_two_byte<'s>(
466 scope: &PinScope<'s, '_, ()>,
467 buffer: &[u16],
468 new_type: NewStringType,
469 ) -> Option<Local<'s, String>> {
470 let buffer_len = buffer.len().try_into().ok()?;
471 unsafe {
472 scope.cast_local(|sd| {
473 v8__String__NewFromTwoByte(
474 sd.get_isolate_ptr(),
475 buffer.as_ptr(),
476 new_type,
477 buffer_len,
478 )
479 })
480 }
481 }
482
483 #[inline(always)]
485 pub fn length(&self) -> usize {
486 unsafe { v8__String__Length(self) as usize }
487 }
488
489 #[inline(always)]
492 pub fn utf8_length(&self, scope: &Isolate) -> usize {
493 unsafe { v8__String__Utf8Length(self, scope.as_real_ptr()) as usize }
494 }
495
496 #[inline(always)]
499 #[deprecated = "Use `v8::String::write_v2` instead"]
500 pub fn write(
501 &self,
502 scope: &Isolate,
503 buffer: &mut [u16],
504 start: usize,
505 options: WriteOptions,
506 ) -> usize {
507 unsafe {
508 v8__String__Write(
509 self,
510 scope.as_real_ptr(),
511 buffer.as_mut_ptr(),
512 start.try_into().unwrap_or(int::MAX),
513 buffer.len().try_into().unwrap_or(int::MAX),
514 options,
515 ) as usize
516 }
517 }
518
519 #[inline(always)]
522 pub fn write_v2(
523 &self,
524 scope: &Isolate,
525 offset: u32,
526 buffer: &mut [u16],
527 flags: WriteFlags,
528 ) {
529 unsafe {
530 v8__String__Write_v2(
531 self,
532 scope.as_real_ptr(),
533 offset,
534 self.length().min(buffer.len()) as _,
535 buffer.as_mut_ptr(),
536 flags.bits(),
537 )
538 }
539 }
540
541 #[inline(always)]
544 #[deprecated = "Use `v8::String::write_one_byte_v2` instead."]
545 pub fn write_one_byte(
546 &self,
547 scope: &Isolate,
548 buffer: &mut [u8],
549 start: usize,
550 options: WriteOptions,
551 ) -> usize {
552 unsafe {
553 v8__String__WriteOneByte(
554 self,
555 scope.as_real_ptr(),
556 buffer.as_mut_ptr(),
557 start.try_into().unwrap_or(int::MAX),
558 buffer.len().try_into().unwrap_or(int::MAX),
559 options,
560 ) as usize
561 }
562 }
563
564 #[inline(always)]
567 pub fn write_one_byte_v2(
568 &self,
569 scope: &Isolate,
570 offset: u32,
571 buffer: &mut [u8],
572 flags: WriteFlags,
573 ) {
574 unsafe {
575 v8__String__WriteOneByte_v2(
576 self,
577 scope.as_real_ptr(),
578 offset,
579 self.length().min(buffer.len()) as _,
580 buffer.as_mut_ptr(),
581 flags.bits(),
582 )
583 }
584 }
585
586 #[inline(always)]
589 #[deprecated = "Use `v8::String::write_one_byte_uninit_v2` instead."]
590 pub fn write_one_byte_uninit(
591 &self,
592 scope: &Isolate,
593 buffer: &mut [MaybeUninit<u8>],
594 start: usize,
595 options: WriteOptions,
596 ) -> usize {
597 unsafe {
598 v8__String__WriteOneByte(
599 self,
600 scope.as_real_ptr(),
601 buffer.as_mut_ptr() as *mut u8,
602 start.try_into().unwrap_or(int::MAX),
603 buffer.len().try_into().unwrap_or(int::MAX),
604 options,
605 ) as usize
606 }
607 }
608
609 #[inline(always)]
612 pub fn write_one_byte_uninit_v2(
613 &self,
614 scope: &Isolate,
615 offset: u32,
616 buffer: &mut [MaybeUninit<u8>],
617 flags: WriteFlags,
618 ) {
619 unsafe {
620 v8__String__WriteOneByte_v2(
621 self,
622 scope.as_real_ptr(),
623 offset,
624 self.length().min(buffer.len()) as _,
625 buffer.as_mut_ptr() as _,
626 flags.bits(),
627 )
628 }
629 }
630
631 #[inline(always)]
633 #[deprecated = "Use `v8::String::write_utf8_v2` instead."]
634 pub fn write_utf8(
635 &self,
636 scope: &mut Isolate,
637 buffer: &mut [u8],
638 nchars_ref: Option<&mut usize>,
639 options: WriteOptions,
640 ) -> usize {
641 unsafe {
642 let buffer = {
646 let len = buffer.len();
647 let data = buffer.as_mut_ptr().cast();
648 slice::from_raw_parts_mut(data, len)
649 };
650 #[allow(deprecated)]
651 self.write_utf8_uninit(scope, buffer, nchars_ref, options)
652 }
653 }
654
655 #[inline(always)]
657 pub fn write_utf8_v2(
658 &self,
659 scope: &Isolate,
660 buffer: &mut [u8],
661 flags: WriteFlags,
662 processed_characters_return: Option<&mut usize>,
663 ) -> usize {
664 unsafe {
665 let buffer = {
670 let len = buffer.len();
671 let data = buffer.as_mut_ptr().cast();
672 slice::from_raw_parts_mut(data, len)
673 };
674 self.write_utf8_uninit_v2(
675 scope,
676 buffer,
677 flags,
678 processed_characters_return,
679 )
680 }
681 }
682
683 #[deprecated = "Use `v8::String::write_utf8_uninit_v2` instead."]
685 pub fn write_utf8_uninit(
686 &self,
687 scope: &Isolate,
688 buffer: &mut [MaybeUninit<u8>],
689 nchars_ref: Option<&mut usize>,
690 options: WriteOptions,
691 ) -> usize {
692 let mut nchars_ref_int: int = 0;
693 let bytes = unsafe {
694 v8__String__WriteUtf8(
695 self,
696 scope.as_real_ptr(),
697 buffer.as_mut_ptr() as *mut char,
698 buffer.len().try_into().unwrap_or(int::MAX),
699 &mut nchars_ref_int,
700 options,
701 )
702 };
703 if let Some(r) = nchars_ref {
704 *r = nchars_ref_int as usize;
705 }
706 bytes as usize
707 }
708
709 pub fn write_utf8_uninit_v2(
711 &self,
712 scope: &Isolate,
713 buffer: &mut [MaybeUninit<u8>],
714 flags: WriteFlags,
715 processed_characters_return: Option<&mut usize>,
716 ) -> usize {
717 let bytes = unsafe {
718 v8__String__WriteUtf8_v2(
719 self,
720 scope.as_real_ptr(),
721 buffer.as_mut_ptr() as _,
722 buffer.len(),
723 flags.bits(),
724 processed_characters_return
725 .map(|p| p as *mut _)
726 .unwrap_or(std::ptr::null_mut()),
727 )
728 };
729 bytes as usize
730 }
731
732 #[inline(always)]
734 pub fn new<'s>(
735 scope: &PinScope<'s, '_, ()>,
736 value: &str,
737 ) -> Option<Local<'s, String>> {
738 Self::new_from_utf8(scope, value.as_ref(), NewStringType::Normal)
739 }
740
741 #[inline(always)]
744 pub const fn create_external_onebyte_const(
745 buffer: &'static [u8],
746 ) -> OneByteConst {
747 assert!(buffer.is_ascii() && buffer.len() <= ((1 << 29) - 24));
750 OneByteConst {
751 vtable: &ONE_BYTE_CONST_VTABLE.delete1,
752 cached_data: buffer.as_ptr() as *const char,
753 length: buffer.len(),
754 }
755 }
756
757 #[inline(always)]
766 pub const unsafe fn create_external_onebyte_const_unchecked(
767 buffer: &'static [u8],
768 ) -> OneByteConst {
769 OneByteConst {
770 vtable: &ONE_BYTE_CONST_VTABLE.delete1,
771 cached_data: buffer.as_ptr() as *const char,
772 length: buffer.len(),
773 }
774 }
775
776 #[inline(always)]
782 pub fn new_from_onebyte_const<'s>(
783 scope: &PinScope<'s, '_, ()>,
784 onebyte_const: &'static OneByteConst,
785 ) -> Option<Local<'s, String>> {
786 unsafe {
787 scope.cast_local(|sd| {
788 v8__String__NewExternalOneByteConst(sd.get_isolate_ptr(), onebyte_const)
789 })
790 }
791 }
792
793 #[inline(always)]
796 pub fn new_external_onebyte_static<'s>(
797 scope: &PinScope<'s, '_, ()>,
798 buffer: &'static [u8],
799 ) -> Option<Local<'s, String>> {
800 let buffer_len = buffer.len().try_into().ok()?;
801 unsafe {
802 scope.cast_local(|sd| {
803 v8__String__NewExternalOneByteStatic(
804 sd.get_isolate_ptr(),
805 buffer.as_ptr() as *const char,
806 buffer_len,
807 )
808 })
809 }
810 }
811
812 #[inline(always)]
816 pub fn new_external_onebyte<'s>(
817 scope: &PinScope<'s, '_, ()>,
818 buffer: Box<[u8]>,
819 ) -> Option<Local<'s, String>> {
820 let buffer_len = buffer.len();
821 unsafe {
822 scope.cast_local(|sd| {
823 v8__String__NewExternalOneByte(
824 sd.get_isolate_ptr(),
825 Box::into_raw(buffer).cast::<char>(),
826 buffer_len,
827 free_rust_external_onebyte,
828 )
829 })
830 }
831 }
832
833 #[inline(always)]
841 pub unsafe fn new_external_onebyte_raw<'s>(
842 scope: &PinScope<'s, '_, ()>,
843 buffer: *mut char,
844 buffer_len: usize,
845 destructor: unsafe extern "C" fn(*mut char, usize),
846 ) -> Option<Local<'s, String>> {
847 unsafe {
848 scope.cast_local(|sd| {
849 v8__String__NewExternalOneByte(
850 sd.get_isolate_ptr(),
851 buffer,
852 buffer_len,
853 destructor,
854 )
855 })
856 }
857 }
858
859 #[inline(always)]
861 pub fn new_external_twobyte_static<'s>(
862 scope: &PinScope<'s, '_, ()>,
863 buffer: &'static [u16],
864 ) -> Option<Local<'s, String>> {
865 let buffer_len = buffer.len().try_into().ok()?;
866 unsafe {
867 scope.cast_local(|sd| {
868 v8__String__NewExternalTwoByteStatic(
869 sd.get_isolate_ptr(),
870 buffer.as_ptr(),
871 buffer_len,
872 )
873 })
874 }
875 }
876
877 #[inline]
881 pub fn get_external_string_resource(
882 &self,
883 ) -> Option<NonNull<ExternalStringResource>> {
884 NonNull::new(unsafe { v8__String__GetExternalStringResource(self) })
885 }
886
887 #[inline]
891 pub fn get_external_onebyte_string_resource(
892 &self,
893 ) -> Option<NonNull<ExternalOneByteStringResource>> {
894 let (base, encoding) = self.get_external_string_resource_base();
895 let base = base?;
896 if encoding != Encoding::OneByte {
897 return None;
898 }
899
900 Some(base.cast())
901 }
902
903 pub fn get_external_string_resource_base(
908 &self,
909 ) -> (Option<NonNull<ExternalStringResourceBase>>, Encoding) {
910 let mut encoding = Encoding::Unknown;
911 (
912 NonNull::new(unsafe {
913 v8__String__GetExternalStringResourceBase(self, &mut encoding)
914 }),
915 encoding,
916 )
917 }
918
919 #[inline(always)]
921 pub fn is_external(&self) -> bool {
922 self.is_external_onebyte() || self.is_external_twobyte()
929 }
930
931 #[inline(always)]
934 pub fn is_external_onebyte(&self) -> bool {
935 unsafe { v8__String__IsExternalOneByte(self) }
936 }
937
938 #[inline(always)]
941 pub fn is_external_twobyte(&self) -> bool {
942 unsafe { v8__String__IsExternalTwoByte(self) }
943 }
944
945 #[inline(always)]
954 pub fn is_onebyte(&self) -> bool {
955 unsafe { v8__String__IsOneByte(self) }
956 }
957
958 #[inline(always)]
961 pub fn contains_only_onebyte(&self) -> bool {
962 unsafe { v8__String__ContainsOnlyOneByte(self) }
963 }
964
965 pub fn to_rust_string_lossy(&self, scope: &Isolate) -> std::string::String {
968 let len_utf16 = self.length();
969
970 if len_utf16 == 0 {
972 return std::string::String::new();
973 }
974
975 let len_utf8 = self.utf8_length(scope);
976
977 if self.is_onebyte() && len_utf8 == len_utf16 {
980 unsafe {
981 let layout = std::alloc::Layout::from_size_align(len_utf16, 1).unwrap();
984 let data = std::alloc::alloc(layout) as *mut MaybeUninit<u8>;
985 let buffer = std::ptr::slice_from_raw_parts_mut(data, len_utf16);
986
987 self.write_one_byte_uninit_v2(
989 scope,
990 0,
991 &mut *buffer,
992 WriteFlags::kReplaceInvalidUtf8,
993 );
994
995 let buffer = data as *mut u8;
997 return std::string::String::from_raw_parts(
998 buffer, len_utf16, len_utf16,
999 );
1000 }
1001 }
1002
1003 unsafe {
1006 let layout = std::alloc::Layout::from_size_align(len_utf8, 1).unwrap();
1009 let data = std::alloc::alloc(layout) as *mut MaybeUninit<u8>;
1010 let buffer = std::ptr::slice_from_raw_parts_mut(data, len_utf8);
1011
1012 let length = self.write_utf8_uninit_v2(
1014 scope,
1015 &mut *buffer,
1016 WriteFlags::kReplaceInvalidUtf8,
1017 None,
1018 );
1019 debug_assert!(length == len_utf8);
1020
1021 let buffer = data as *mut u8;
1023 std::string::String::from_raw_parts(buffer, length, len_utf8)
1024 }
1025 }
1026
1027 pub fn to_rust_cow_lossy<'a, const N: usize>(
1030 &self,
1031 scope: &mut Isolate,
1032 buffer: &'a mut [MaybeUninit<u8>; N],
1033 ) -> Cow<'a, str> {
1034 let len_utf16 = self.length();
1035
1036 if len_utf16 == 0 {
1038 return "".into();
1039 }
1040
1041 let len_utf8 = self.utf8_length(scope);
1043
1044 if self.is_onebyte() && len_utf8 == len_utf16 {
1047 if len_utf16 <= N {
1048 self.write_one_byte_uninit_v2(scope, 0, buffer, WriteFlags::empty());
1049 unsafe {
1050 let buffer = &mut buffer[..len_utf16];
1052 let buffer = &mut *(buffer as *mut [_] as *mut [u8]);
1053
1054 return Cow::Borrowed(std::str::from_utf8_unchecked(buffer));
1056 }
1057 }
1058
1059 unsafe {
1060 let layout = std::alloc::Layout::from_size_align(len_utf16, 1).unwrap();
1063 let data = std::alloc::alloc(layout) as *mut MaybeUninit<u8>;
1064 let buffer = std::ptr::slice_from_raw_parts_mut(data, len_utf16);
1065
1066 self.write_one_byte_uninit_v2(
1068 scope,
1069 0,
1070 &mut *buffer,
1071 WriteFlags::kReplaceInvalidUtf8,
1072 );
1073
1074 let buffer = data as *mut u8;
1076 return Cow::Owned(std::string::String::from_raw_parts(
1077 buffer, len_utf16, len_utf16,
1078 ));
1079 }
1080 }
1081
1082 if len_utf8 <= N {
1083 let length = self.write_utf8_uninit_v2(
1085 scope,
1086 buffer,
1087 WriteFlags::kReplaceInvalidUtf8,
1088 None,
1089 );
1090 debug_assert!(length == len_utf8);
1091
1092 unsafe {
1094 let buffer = &mut buffer[..length];
1096 let buffer = &mut *(buffer as *mut [_] as *mut [u8]);
1097
1098 return Cow::Borrowed(std::str::from_utf8_unchecked(buffer));
1100 }
1101 }
1102
1103 unsafe {
1106 let layout = std::alloc::Layout::from_size_align(len_utf8, 1).unwrap();
1109 let data = std::alloc::alloc(layout) as *mut MaybeUninit<u8>;
1110 let buffer = std::ptr::slice_from_raw_parts_mut(data, len_utf8);
1111
1112 let length = self.write_utf8_uninit_v2(
1114 scope,
1115 &mut *buffer,
1116 WriteFlags::kReplaceInvalidUtf8,
1117 None,
1118 );
1119 debug_assert!(length == len_utf8);
1120
1121 let buffer = data as *mut u8;
1123 Cow::Owned(std::string::String::from_raw_parts(
1124 buffer, length, len_utf8,
1125 ))
1126 }
1127 }
1128}
1129
1130#[inline]
1131pub unsafe extern "C" fn free_rust_external_onebyte(s: *mut char, len: usize) {
1132 unsafe {
1133 let slice = std::slice::from_raw_parts_mut(s, len);
1134
1135 drop(Box::from_raw(slice));
1137 }
1138}
1139
1140#[derive(Debug, PartialEq)]
1141pub enum ValueViewData<'s> {
1142 OneByte(&'s [u8]),
1143 TwoByte(&'s [u16]),
1144}
1145
1146#[repr(C)]
1155pub struct ValueView<'s>(
1156 [u8; crate::binding::v8__String__ValueView_SIZE],
1157 PhantomData<&'s ()>,
1158);
1159
1160impl<'s> ValueView<'s> {
1161 #[inline(always)]
1162 pub fn new(isolate: &mut Isolate, string: Local<'s, String>) -> Self {
1163 let mut v = std::mem::MaybeUninit::uninit();
1164 unsafe {
1165 v8__String__ValueView__CONSTRUCT(
1166 v.as_mut_ptr(),
1167 isolate.as_real_ptr(),
1168 &*string,
1169 );
1170 v.assume_init()
1171 }
1172 }
1173
1174 #[inline(always)]
1175 pub fn data(&self) -> ValueViewData<'_> {
1176 unsafe {
1177 let data = v8__String__ValueView__data(self);
1178 let length = v8__String__ValueView__length(self) as usize;
1179 if v8__String__ValueView__is_one_byte(self) {
1180 ValueViewData::OneByte(std::slice::from_raw_parts(data as _, length))
1181 } else {
1182 ValueViewData::TwoByte(std::slice::from_raw_parts(data as _, length))
1183 }
1184 }
1185 }
1186}
1187
1188impl Drop for ValueView<'_> {
1189 fn drop(&mut self) {
1190 unsafe { v8__String__ValueView__DESTRUCT(self) }
1191 }
1192}