diff --git a/src/binding.cc b/src/binding.cc index bf6a44ec..b2853d3d 100644 --- a/src/binding.cc +++ b/src/binding.cc @@ -34,6 +34,9 @@ using namespace support; +// TODO(bartlomieju): ideally we could ignore only some of the deprecated APIs +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + template constexpr size_t align_to(size_t size) { return (size + sizeof(T) - 1) & ~(sizeof(T) - 1); @@ -1082,20 +1085,37 @@ int v8__String__Utf8Length(const v8::String& self, v8::Isolate* isolate) { return self.Utf8LengthV2(isolate); } -void v8__String__Write(const v8::String& self, v8::Isolate* isolate, - uint32_t offset, uint32_t length, uint16_t* buffer, - int flags) { +int v8__String__Write(const v8::String& self, v8::Isolate* isolate, + uint16_t* buffer, int start, int length, int options) { + return self.Write(isolate, buffer, start, length, options); +} + +void v8__String__Write_v2(const v8::String& self, v8::Isolate* isolate, + uint32_t offset, uint32_t length, uint16_t* buffer, + int flags) { return self.WriteV2(isolate, offset, length, buffer, flags); } -void v8__String__WriteOneByte(const v8::String& self, v8::Isolate* isolate, - uint32_t offset, uint32_t length, uint8_t* buffer, - int flags) { +int v8__String__WriteOneByte(const v8::String& self, v8::Isolate* isolate, + uint8_t* buffer, int start, int length, + int options) { + return self.WriteOneByte(isolate, buffer, start, length, options); +} + +void v8__String__WriteOneByte_v2(const v8::String& self, v8::Isolate* isolate, + uint32_t offset, uint32_t length, + uint8_t* buffer, int flags) { return self.WriteOneByteV2(isolate, offset, length, buffer, flags); } -size_t v8__String__WriteUtf8(const v8::String& self, v8::Isolate* isolate, - char* buffer, size_t capacity, int flags) { +int v8__String__WriteUtf8(const v8::String& self, v8::Isolate* isolate, + char* buffer, int length, int* nchars_ref, + int options) { + return self.WriteUtf8(isolate, buffer, length, nchars_ref, options); +} + +size_t v8__String__WriteUtf8_v2(const v8::String& self, v8::Isolate* isolate, + char* buffer, size_t capacity, int flags) { return self.WriteUtf8V2(isolate, buffer, capacity, flags); } diff --git a/src/string.rs b/src/string.rs index bf94296c..3d354ae0 100644 --- a/src/string.rs +++ b/src/string.rs @@ -45,6 +45,15 @@ extern "C" { fn v8__String__Utf8Length(this: *const String, isolate: *mut Isolate) -> int; fn v8__String__Write( + this: *const String, + isolate: *mut Isolate, + buffer: *mut u16, + start: int, + length: int, + options: WriteOptions, + ) -> int; + + fn v8__String__Write_v2( this: *const String, isolate: *mut Isolate, offset: u32, @@ -54,6 +63,15 @@ extern "C" { ); fn v8__String__WriteOneByte( + this: *const String, + isolate: *mut Isolate, + buffer: *mut u8, + start: int, + length: int, + options: WriteOptions, + ) -> int; + + fn v8__String__WriteOneByte_v2( this: *const String, isolate: *mut Isolate, offset: u32, @@ -63,6 +81,15 @@ extern "C" { ); fn v8__String__WriteUtf8( + this: *const String, + isolate: *mut Isolate, + buffer: *mut char, + length: int, + nchars_ref: *mut int, + options: WriteOptions, + ) -> int; + + fn v8__String__WriteUtf8_v2( this: *const String, isolate: *mut Isolate, buffer: *mut char, @@ -325,6 +352,21 @@ pub enum NewStringType { Internalized, } +bitflags! { + #[derive(Clone, Copy, Default)] + #[repr(transparent)] + pub struct WriteOptions: int { + const NO_OPTIONS = 0; + const HINT_MANY_WRITES_EXPECTED = 1; + const NO_NULL_TERMINATION = 2; + const PRESERVE_ONE_BYTE_NULL = 4; + // Used by WriteUtf8 to replace orphan surrogate code units with the + // unicode replacement character. Needs to be set to guarantee valid UTF-8 + // output. + const REPLACE_INVALID_UTF8 = 8; + } +} + bitflags! { #[derive(Clone, Copy, Default)] #[repr(transparent)] @@ -430,7 +472,30 @@ impl String { /// Writes the contents of the string to an external buffer, as 16-bit /// (UTF-16) character codes. #[inline(always)] + #[deprecated = "Use `v8::String::write_v2` instead"] pub fn write( + &self, + scope: &mut Isolate, + buffer: &mut [u16], + start: usize, + options: WriteOptions, + ) -> usize { + unsafe { + v8__String__Write( + self, + scope, + buffer.as_mut_ptr(), + start.try_into().unwrap_or(int::MAX), + buffer.len().try_into().unwrap_or(int::MAX), + options, + ) as usize + } + } + + /// Writes the contents of the string to an external buffer, as 16-bit + /// (UTF-16) character codes. + #[inline(always)] + pub fn write_v2( &self, scope: &mut Isolate, offset: u32, @@ -438,7 +503,7 @@ impl String { flags: WriteFlags, ) { unsafe { - v8__String__Write( + v8__String__Write_v2( self, scope, offset, @@ -452,7 +517,30 @@ impl String { /// Writes the contents of the string to an external buffer, as one-byte /// (Latin-1) characters. #[inline(always)] + #[deprecated = "Use `v8::String::write_one_byte_v2` instead."] pub fn write_one_byte( + &self, + scope: &mut Isolate, + buffer: &mut [u8], + start: usize, + options: WriteOptions, + ) -> usize { + unsafe { + v8__String__WriteOneByte( + self, + scope, + buffer.as_mut_ptr(), + start.try_into().unwrap_or(int::MAX), + buffer.len().try_into().unwrap_or(int::MAX), + options, + ) as usize + } + } + + /// Writes the contents of the string to an external buffer, as one-byte + /// (Latin-1) characters. + #[inline(always)] + pub fn write_one_byte_v2( &self, scope: &mut Isolate, offset: u32, @@ -460,7 +548,7 @@ impl String { flags: WriteFlags, ) { unsafe { - v8__String__WriteOneByte( + v8__String__WriteOneByte_v2( self, scope, offset, @@ -474,7 +562,30 @@ impl String { /// Writes the contents of the string to an external [`MaybeUninit`] buffer, as one-byte /// (Latin-1) characters. #[inline(always)] + #[deprecated = "Use `v8::String::write_one_byte_uninit_v2` instead."] pub fn write_one_byte_uninit( + &self, + scope: &mut Isolate, + buffer: &mut [MaybeUninit], + start: usize, + options: WriteOptions, + ) -> usize { + unsafe { + v8__String__WriteOneByte( + self, + scope, + buffer.as_mut_ptr() as *mut u8, + start.try_into().unwrap_or(int::MAX), + buffer.len().try_into().unwrap_or(int::MAX), + options, + ) as usize + } + } + + /// Writes the contents of the string to an external [`MaybeUninit`] buffer, as one-byte + /// (Latin-1) characters. + #[inline(always)] + pub fn write_one_byte_uninit_v2( &self, scope: &mut Isolate, offset: u32, @@ -482,7 +593,7 @@ impl String { flags: WriteFlags, ) { unsafe { - v8__String__WriteOneByte( + v8__String__WriteOneByte_v2( self, scope, offset, @@ -495,7 +606,31 @@ impl String { /// Writes the contents of the string to an external buffer, as UTF-8. #[inline(always)] + #[deprecated = "Use `v8::String::write_utf8_v2` instead."] pub fn write_utf8( + &self, + scope: &mut Isolate, + buffer: &mut [u8], + nchars_ref: Option<&mut usize>, + options: WriteOptions, + ) -> usize { + unsafe { + // SAFETY: + // We assume that v8 will overwrite the buffer without de-initializing any byte in it. + // So the type casting of the buffer is safe. + let buffer = { + let len = buffer.len(); + let data = buffer.as_mut_ptr().cast(); + slice::from_raw_parts_mut(data, len) + }; + #[allow(deprecated)] + self.write_utf8_uninit(scope, buffer, nchars_ref, options) + } + } + + /// Writes the contents of the string to an external buffer, as UTF-8. + #[inline(always)] + pub fn write_utf8_v2( &self, scope: &mut Isolate, buffer: &mut [u8], @@ -511,19 +646,45 @@ impl String { let data = buffer.as_mut_ptr().cast(); slice::from_raw_parts_mut(data, len) }; - self.write_utf8_uninit(scope, buffer, flags) + self.write_utf8_uninit_v2(scope, buffer, flags) } } /// Writes the contents of the string to an external [`MaybeUninit`] buffer, as UTF-8. + #[deprecated = "Use `v8::String::write_utf8_uninit_v2` instead."] pub fn write_utf8_uninit( + &self, + scope: &mut Isolate, + buffer: &mut [MaybeUninit], + nchars_ref: Option<&mut usize>, + options: WriteOptions, + ) -> usize { + let mut nchars_ref_int: int = 0; + let bytes = unsafe { + v8__String__WriteUtf8( + self, + scope, + buffer.as_mut_ptr() as *mut char, + buffer.len().try_into().unwrap_or(int::MAX), + &mut nchars_ref_int, + options, + ) + }; + if let Some(r) = nchars_ref { + *r = nchars_ref_int as usize; + } + bytes as usize + } + + /// Writes the contents of the string to an external [`MaybeUninit`] buffer, as UTF-8. + pub fn write_utf8_uninit_v2( &self, scope: &mut Isolate, buffer: &mut [MaybeUninit], flags: WriteFlags, ) -> usize { let bytes = unsafe { - v8__String__WriteUtf8( + v8__String__WriteUtf8_v2( self, scope, buffer.as_mut_ptr() as _, @@ -791,7 +952,7 @@ impl String { let buffer = std::ptr::slice_from_raw_parts_mut(data, len_utf16); // Write to this MaybeUninit buffer, assuming we're going to fill this entire buffer - self.write_one_byte_uninit( + self.write_one_byte_uninit_v2( scope, 0, &mut *buffer, @@ -816,7 +977,7 @@ impl String { let buffer = std::ptr::slice_from_raw_parts_mut(data, len_utf8); // Write to this MaybeUninit buffer, assuming we're going to fill this entire buffer - let length = self.write_utf8_uninit( + let length = self.write_utf8_uninit_v2( scope, &mut *buffer, WriteFlags::kReplaceInvalidUtf8, @@ -850,7 +1011,7 @@ impl String { // string is 100% 7-bit ASCII. if self.is_onebyte() && len_utf8 == len_utf16 { if len_utf16 <= N { - self.write_one_byte_uninit(scope, 0, buffer, WriteFlags::empty()); + self.write_one_byte_uninit_v2(scope, 0, buffer, WriteFlags::empty()); unsafe { // Get a slice of &[u8] of what we know is initialized now let buffer = &mut buffer[..len_utf16]; @@ -869,7 +1030,7 @@ impl String { let buffer = std::ptr::slice_from_raw_parts_mut(data, len_utf16); // Write to this MaybeUninit buffer, assuming we're going to fill this entire buffer - self.write_one_byte_uninit( + self.write_one_byte_uninit_v2( scope, 0, &mut *buffer, @@ -886,8 +1047,11 @@ impl String { if len_utf8 <= N { // No malloc path - let length = - self.write_utf8_uninit(scope, buffer, WriteFlags::kReplaceInvalidUtf8); + let length = self.write_utf8_uninit_v2( + scope, + buffer, + WriteFlags::kReplaceInvalidUtf8, + ); debug_assert!(length == len_utf8); // SAFETY: We know that we wrote `length` UTF-8 bytes. See `slice_assume_init_mut` for additional guarantee information. @@ -911,7 +1075,7 @@ impl String { let buffer = std::ptr::slice_from_raw_parts_mut(data, len_utf8); // Write to this MaybeUninit buffer, assuming we're going to fill this entire buffer - let length = self.write_utf8_uninit( + let length = self.write_utf8_uninit_v2( scope, &mut *buffer, WriteFlags::kReplaceInvalidUtf8, diff --git a/tests/test_api.rs b/tests/test_api.rs index 9879983b..4f8a406e 100644 --- a/tests/test_api.rs +++ b/tests/test_api.rs @@ -265,10 +265,10 @@ fn test_string() { let mut vec = vec![0; 17]; assert_eq!( 17, - local.write_utf8(scope, &mut vec, v8::WriteFlags::empty()) + local.write_utf8_v2(scope, &mut vec, v8::WriteFlags::empty()) ); let mut u16_buffer = [0u16; 16]; - local.write(scope, 0, &mut u16_buffer, v8::WriteFlags::empty()); + local.write_v2(scope, 0, &mut u16_buffer, v8::WriteFlags::empty()); assert_eq!( String::from(reference), String::from_utf16(&u16_buffer[..15]).unwrap() @@ -297,7 +297,7 @@ fn test_string() { assert_eq!(3, local.length()); assert_eq!(3, local.utf8_length(scope)); let mut buffer = [0u8; 3]; - local.write_one_byte(scope, 0, &mut buffer, v8::WriteFlags::empty()); + local.write_one_byte_v2(scope, 0, &mut buffer, v8::WriteFlags::empty()); assert_eq!(b"foo", &buffer); assert_eq!("foo", local.to_rust_string_lossy(scope)); }