2019-12-04 02:03:17 -05:00
|
|
|
use std::convert::TryInto;
|
|
|
|
use std::default::Default;
|
|
|
|
use std::mem::forget;
|
|
|
|
use std::slice;
|
|
|
|
|
|
|
|
use crate::support::char;
|
|
|
|
use crate::support::int;
|
2019-12-24 18:31:36 -05:00
|
|
|
use crate::InIsolate;
|
|
|
|
use crate::Isolate;
|
2019-12-04 02:03:17 -05:00
|
|
|
use crate::Local;
|
2019-12-30 09:28:39 -05:00
|
|
|
use crate::String;
|
2019-12-24 18:31:36 -05:00
|
|
|
use crate::ToLocal;
|
2019-12-04 02:03:17 -05:00
|
|
|
|
|
|
|
extern "C" {
|
2020-01-22 11:23:42 -05:00
|
|
|
fn v8__String__Empty(isolate: *mut Isolate) -> *mut String;
|
|
|
|
|
2019-12-04 02:03:17 -05:00
|
|
|
fn v8__String__NewFromUtf8(
|
2019-12-20 10:01:45 -05:00
|
|
|
isolate: *mut Isolate,
|
2019-12-04 02:03:17 -05:00
|
|
|
data: *const char,
|
|
|
|
new_type: NewStringType,
|
|
|
|
length: int,
|
2019-12-04 08:12:27 -05:00
|
|
|
) -> *mut String;
|
2019-12-04 02:03:17 -05:00
|
|
|
|
2019-12-05 12:28:20 -05:00
|
|
|
fn v8__String__Length(this: &String) -> int;
|
|
|
|
|
2019-12-20 10:01:45 -05:00
|
|
|
fn v8__String__Utf8Length(this: &String, isolate: *mut Isolate) -> int;
|
2019-12-04 02:03:17 -05:00
|
|
|
|
|
|
|
fn v8__String__WriteUtf8(
|
|
|
|
this: &String,
|
2019-12-20 10:01:45 -05:00
|
|
|
isolate: *mut Isolate,
|
2019-12-04 02:03:17 -05:00
|
|
|
buffer: *mut char,
|
|
|
|
length: int,
|
|
|
|
nchars_ref: *mut int,
|
|
|
|
options: WriteOptions,
|
|
|
|
) -> int;
|
|
|
|
}
|
|
|
|
|
|
|
|
#[repr(C)]
|
|
|
|
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;
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl String {
|
2020-01-22 17:21:56 -05:00
|
|
|
pub fn empty<'sc>(scope: &mut impl ToLocal<'sc>) -> Local<'sc, String> {
|
2020-01-22 11:23:42 -05:00
|
|
|
let ptr = unsafe { v8__String__Empty(scope.isolate()) };
|
|
|
|
// FIXME(bnoordhuis) v8__String__Empty() is infallible so there
|
|
|
|
// is no need to box up the result, only to unwrap it again.
|
|
|
|
unsafe { scope.to_local(ptr) }.unwrap()
|
|
|
|
}
|
|
|
|
|
2019-12-20 10:01:45 -05:00
|
|
|
pub fn new_from_utf8<'sc>(
|
2019-12-24 18:31:36 -05:00
|
|
|
scope: &mut impl ToLocal<'sc>,
|
2019-12-04 02:03:17 -05:00
|
|
|
buffer: &[u8],
|
|
|
|
new_type: NewStringType,
|
2019-12-20 10:01:45 -05:00
|
|
|
) -> Option<Local<'sc, String>> {
|
2020-01-22 11:23:42 -05:00
|
|
|
if buffer.is_empty() {
|
2020-01-22 17:21:56 -05:00
|
|
|
return Some(Self::empty(scope));
|
2020-01-22 11:23:42 -05:00
|
|
|
}
|
2019-12-24 18:31:36 -05:00
|
|
|
let ptr = unsafe {
|
|
|
|
v8__String__NewFromUtf8(
|
|
|
|
scope.isolate(),
|
2019-12-04 02:03:17 -05:00
|
|
|
buffer.as_ptr() as *const char,
|
|
|
|
new_type,
|
|
|
|
buffer.len().try_into().ok()?,
|
2019-12-24 18:31:36 -05:00
|
|
|
)
|
|
|
|
};
|
|
|
|
unsafe { scope.to_local(ptr) }
|
2019-12-04 02:03:17 -05:00
|
|
|
}
|
|
|
|
|
2019-12-05 12:28:20 -05:00
|
|
|
/// Returns the number of characters (UTF-16 code units) in this string.
|
|
|
|
pub fn length(&self) -> usize {
|
|
|
|
unsafe { v8__String__Length(self) as usize }
|
|
|
|
}
|
|
|
|
|
2019-12-05 17:03:18 -05:00
|
|
|
/// Returns the number of bytes in the UTF-8 encoded representation of this
|
|
|
|
/// string.
|
2019-12-24 18:31:36 -05:00
|
|
|
pub fn utf8_length(&self, scope: &mut impl InIsolate) -> usize {
|
|
|
|
unsafe { v8__String__Utf8Length(self, scope.isolate()) as usize }
|
2019-12-04 02:03:17 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn write_utf8(
|
|
|
|
&self,
|
2019-12-24 18:31:36 -05:00
|
|
|
scope: &mut impl InIsolate,
|
2019-12-04 02:03:17 -05:00
|
|
|
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,
|
2019-12-24 18:31:36 -05:00
|
|
|
scope.isolate(),
|
2019-12-04 02:03:17 -05:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
|
|
// Convenience function not present in the original V8 API.
|
2019-12-20 10:01:45 -05:00
|
|
|
pub fn new<'sc>(
|
2019-12-24 18:31:36 -05:00
|
|
|
scope: &mut impl ToLocal<'sc>,
|
2019-12-04 02:03:17 -05:00
|
|
|
value: &str,
|
2019-12-20 10:01:45 -05:00
|
|
|
) -> Option<Local<'sc, String>> {
|
2019-12-20 20:59:56 -05:00
|
|
|
Self::new_from_utf8(scope, value.as_ref(), NewStringType::Normal)
|
2019-12-04 02:03:17 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// Convenience function not present in the original V8 API.
|
2019-12-20 10:01:45 -05:00
|
|
|
pub fn to_rust_string_lossy(
|
|
|
|
&self,
|
2019-12-24 18:31:36 -05:00
|
|
|
scope: &mut impl InIsolate,
|
2019-12-20 10:01:45 -05:00
|
|
|
) -> std::string::String {
|
2019-12-24 18:31:36 -05:00
|
|
|
let capacity = self.utf8_length(scope);
|
2019-12-04 02:03:17 -05:00
|
|
|
let mut string = std::string::String::with_capacity(capacity);
|
|
|
|
let data = string.as_mut_ptr();
|
|
|
|
forget(string);
|
|
|
|
let length = self.write_utf8(
|
2019-12-24 18:31:36 -05:00
|
|
|
scope,
|
2019-12-04 02:03:17 -05:00
|
|
|
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) }
|
|
|
|
}
|
|
|
|
}
|