use std::convert::TryInto;
use std::default::Default;
use std::mem::forget;
use std::slice;
use crate::support::char;
use crate::support::int;
use crate::HandleScope;
use crate::Isolate;
use crate::Local;
use crate::String;
extern "C" {
fn v8__String__Empty(isolate: *mut Isolate) -> *const String;
fn v8__String__NewFromUtf8(
isolate: *mut Isolate,
data: *const char,
new_type: NewStringType,
length: int,
) -> *const String;
fn v8__String__NewFromOneByte(
isolate: *mut Isolate,
data: *const u8,
new_type: NewStringType,
length: int,
) -> *const String;
fn v8__String__NewFromTwoByte(
isolate: *mut Isolate,
data: *const u16,
new_type: NewStringType,
length: int,
) -> *const String;
fn v8__String__Length(this: *const String) -> int;
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__WriteOneByte(
this: *const String,
isolate: *mut Isolate,
buffer: *mut u8,
start: int,
length: int,
options: WriteOptions,
) -> int;
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__NewExternalOneByteStatic(
isolate: *mut Isolate,
buffer: *const char,
length: int,
) -> *const String;
fn v8__String__NewExternalTwoByteStatic(
isolate: *mut Isolate,
buffer: *const u16,
length: int,
) -> *const String;
fn v8__String__IsExternal(this: *const String) -> bool;
fn v8__String__IsExternalOneByte(this: *const String) -> bool;
fn v8__String__IsExternalTwoByte(this: *const String) -> bool;
fn v8__String__IsOneByte(this: *const String) -> bool;
fn v8__String__ContainsOnlyOneByte(this: *const String) -> bool;
}
#[repr(C)]
#[derive(Debug)]
pub enum NewStringType {
Normal,
Internalized,
}
impl Default for NewStringType {
fn default() -> Self {
NewStringType::Normal
}
}
bitflags! {
#[derive(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;
const REPLACE_INVALID_UTF8 = 8;
}
}
impl String {
pub fn empty<'s>(scope: &mut HandleScope<'s, ()>) -> Local<'s, String> {
unsafe { scope.cast_local(|sd| v8__String__Empty(sd.get_isolate_ptr())) }
.unwrap()
}
pub fn new_from_utf8<'s>(
scope: &mut HandleScope<'s, ()>,
buffer: &[u8],
new_type: NewStringType,
) -> Option<Local<'s, String>> {
if buffer.is_empty() {
return Some(Self::empty(scope));
}
let buffer_len = buffer.len().try_into().ok()?;
unsafe {
scope.cast_local(|sd| {
v8__String__NewFromUtf8(
sd.get_isolate_ptr(),
buffer.as_ptr() as *const char,
new_type,
buffer_len,
)
})
}
}
pub fn new_from_one_byte<'s>(
scope: &mut HandleScope<'s, ()>,
buffer: &[u8],
new_type: NewStringType,
) -> Option<Local<'s, String>> {
let buffer_len = buffer.len().try_into().ok()?;
unsafe {
scope.cast_local(|sd| {
v8__String__NewFromOneByte(
sd.get_isolate_ptr(),
buffer.as_ptr(),
new_type,
buffer_len,
)
})
}
}
pub fn new_from_two_byte<'s>(
scope: &mut HandleScope<'s, ()>,
buffer: &[u16],
new_type: NewStringType,
) -> Option<Local<'s, String>> {
let buffer_len = buffer.len().try_into().ok()?;
unsafe {
scope.cast_local(|sd| {
v8__String__NewFromTwoByte(
sd.get_isolate_ptr(),
buffer.as_ptr(),
new_type,
buffer_len,
)
})
}
}
pub fn length(&self) -> usize {
unsafe { v8__String__Length(self) as usize }
}
pub fn utf8_length(&self, scope: &mut Isolate) -> usize {
unsafe { v8__String__Utf8Length(self, scope) as usize }
}
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_value()),
buffer.len().try_into().unwrap_or(int::max_value()),
options,
) as usize
}
}
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_value()),
buffer.len().try_into().unwrap_or(int::max_value()),
options,
) as usize
}
}
pub fn write_utf8(
&self,
scope: &mut Isolate,
buffer: &mut [u8],
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_value()),
&mut nchars_ref_int,
options,
)
};
if let Some(r) = nchars_ref {
*r = nchars_ref_int as usize;
}
bytes as usize
}
pub fn new<'s>(
scope: &mut HandleScope<'s, ()>,
value: &str,
) -> Option<Local<'s, String>> {
Self::new_from_utf8(scope, value.as_ref(), NewStringType::Normal)
}
pub fn new_external_onebyte_static<'s>(
scope: &mut HandleScope<'s, ()>,
buffer: &'static [u8],
) -> Option<Local<'s, String>> {
let buffer_len = buffer.len().try_into().ok()?;
unsafe {
scope.cast_local(|sd| {
v8__String__NewExternalOneByteStatic(
sd.get_isolate_ptr(),
buffer.as_ptr() as *const char,
buffer_len,
)
})
}
}
pub fn new_external_twobyte_static<'s>(
scope: &mut HandleScope<'s, ()>,
buffer: &'static [u16],
) -> Option<Local<'s, String>> {
let buffer_len = buffer.len().try_into().ok()?;
unsafe {
scope.cast_local(|sd| {
v8__String__NewExternalTwoByteStatic(
sd.get_isolate_ptr(),
buffer.as_ptr(),
buffer_len,
)
})
}
}
pub fn is_external(&self) -> bool {
self.is_external_onebyte() || self.is_external_twobyte()
}
pub fn is_external_onebyte(&self) -> bool {
unsafe { v8__String__IsExternalOneByte(self) }
}
pub fn is_external_twobyte(&self) -> bool {
unsafe { v8__String__IsExternalTwoByte(self) }
}
pub fn is_onebyte(&self) -> bool {
unsafe { v8__String__IsExternalOneByte(self) }
}
pub fn contains_only_onebyte(&self) -> bool {
unsafe { v8__String__ContainsOnlyOneByte(self) }
}
pub fn to_rust_string_lossy(
&self,
scope: &mut Isolate,
) -> std::string::String {
let capacity = self.utf8_length(scope);
let mut string = std::string::String::with_capacity(capacity);
let data = string.as_mut_ptr();
forget(string);
let length = self.write_utf8(
scope,
unsafe { slice::from_raw_parts_mut(data, capacity) },
None,
WriteOptions::NO_NULL_TERMINATION | WriteOptions::REPLACE_INVALID_UTF8,
);
unsafe { std::string::String::from_raw_parts(data, length, capacity) }
}
}