0
0
Fork 0
mirror of https://github.com/denoland/rusty_v8.git synced 2024-11-21 15:04:33 -05:00

Basic Local<String> support (#27)

This commit is contained in:
Bert Belder 2019-12-04 08:03:17 +01:00
parent cec2467245
commit d91f0269fa
No known key found for this signature in database
GPG key ID: 7A77887B2E2ED461
13 changed files with 209 additions and 6 deletions

View file

@ -10,10 +10,11 @@ v8_static_library("rusty_v8") {
"src/inspector/client.cc",
"src/isolate.cc",
"src/locker.cc",
"src/number.cc",
"src/platform/mod.cc",
"src/platform/task.cc",
"src/string.cc",
"src/string_buffer.cc",
"src/value.cc",
]
deps = [
":v8",

7
Cargo.lock generated
View file

@ -20,6 +20,11 @@ dependencies = [
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "bitflags"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "cargo_gn"
version = "0.0.13"
@ -62,6 +67,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
name = "rusty_v8"
version = "0.0.7"
dependencies = [
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"cargo_gn 0.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
@ -80,6 +86,7 @@ dependencies = [
[metadata]
"checksum backtrace 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)" = "924c76597f0d9ca25d762c25a4d369d51267536465dc5064bdf0eb073ed477ea"
"checksum backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6575f128516de27e3ce99689419835fce9643a9b215a14d2b5b685be018491"
"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
"checksum cargo_gn 0.0.13 (registry+https://github.com/rust-lang/crates.io-index)" = "0a679c108cad6ee19a25f4dbaf1b4e1fadf303e707fa1e2d060b4c169faeb836"
"checksum cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)" = "4fc9a35e1f4290eb9e5fc54ba6cf40671ed2a2514c3eeb2b2a908dda2ea5a1be"
"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"

View file

@ -50,6 +50,7 @@ exclude = [
[dependencies]
lazy_static = "1.4.0"
libc = "0.2.65"
bitflags = "1.2.1"
[build-dependencies]
cargo_gn = "0.0.13"

View file

@ -5,6 +5,8 @@
#![allow(clippy::new_without_default)]
#![allow(dead_code)]
#[macro_use]
extern crate bitflags;
#[macro_use]
extern crate lazy_static;
extern crate libc;
@ -14,13 +16,14 @@ mod inspector;
mod isolate;
mod local;
mod locker;
mod number;
mod string_buffer;
mod string_view;
mod support;
mod value;
pub mod array_buffer;
pub mod platform;
pub mod string;
// This module is intentionally named "V8" rather than "v8" to match the
// C++ namespace "v8::V8".
#[allow(non_snake_case)]
@ -30,6 +33,7 @@ pub use handle_scope::HandleScope;
pub use isolate::Isolate;
pub use local::Local;
pub use locker::Locker;
pub use number::{Integer, Number};
pub use string::String;
pub use string_buffer::StringBuffer;
pub use string_view::StringView;
pub use value::{Integer, Number};

29
src/string.cc Normal file
View file

@ -0,0 +1,29 @@
#include <cstdint>
#include "support.h"
#include "v8/include/v8.h"
using namespace v8;
using namespace support;
extern "C" {
String* v8__String__NewFromUtf8(Isolate* isolate,
const char* data,
NewStringType type,
int length) {
return maybe_local_ptr(String::NewFromUtf8(isolate, data, type, length));
}
int v8__String__Utf8Length(const String& self, Isolate* isolate) {
return self.Utf8Length(isolate);
}
int v8__String__WriteUtf8(const String& self,
Isolate* isolate,
char* buffer,
int length,
int* nchars_ref,
int options) {
return self.WriteUtf8(isolate, buffer, length, nchars_ref, options);
}
}

135
src/string.rs Normal file
View file

@ -0,0 +1,135 @@
use std::convert::TryInto;
use std::default::Default;
use std::mem::forget;
use std::slice;
use crate::isolate::CxxIsolate;
use crate::isolate::LockedIsolate;
use crate::support::char;
use crate::support::int;
use crate::support::Opaque;
use crate::HandleScope;
use crate::Local;
extern "C" {
fn v8__String__NewFromUtf8(
isolate: *mut CxxIsolate,
data: *const char,
new_type: NewStringType,
length: int,
) -> *const String;
fn v8__String__Utf8Length(this: &String, isolate: *mut CxxIsolate) -> int;
fn v8__String__WriteUtf8(
this: &String,
isolate: *mut CxxIsolate,
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;
}
}
#[repr(C)]
pub struct String(Opaque);
impl String {
pub fn new_from_utf8<'sc>(
scope: &mut HandleScope<'sc>,
buffer: &[u8],
new_type: NewStringType,
) -> Option<Local<'sc, String>> {
unsafe {
let ptr = v8__String__NewFromUtf8(
scope.cxx_isolate(),
buffer.as_ptr() as *const char,
new_type,
buffer.len().try_into().ok()?,
);
Local::from_raw(ptr)
}
}
pub fn utf8_length(&self, isolate: &mut impl LockedIsolate) -> usize {
unsafe { v8__String__Utf8Length(self, isolate.cxx_isolate()) as usize }
}
pub fn write_utf8(
&self,
isolate: &mut impl LockedIsolate,
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,
isolate.cxx_isolate(),
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.
pub fn new<'sc>(
scope: &mut HandleScope<'sc>,
value: &str,
new_type: NewStringType,
) -> Option<Local<'sc, String>> {
Self::new_from_utf8(scope, value.as_ref(), new_type)
}
// Convenience function not present in the original V8 API.
pub fn to_rust_string_lossy(
&self,
isolate: &mut impl LockedIsolate,
) -> std::string::String {
let capacity = self.utf8_length(isolate);
let mut string = std::string::String::with_capacity(capacity);
let data = string.as_mut_ptr();
forget(string);
let length = self.write_utf8(
isolate,
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) }
}
}

View file

@ -7,6 +7,8 @@
#include <type_traits>
#include <utility>
#include "v8/include/v8.h"
// Check assumptions made in binding code.
// TODO(ry) re-enable the following
// static_assert(sizeof(bool) == sizeof(uint8_t));
@ -33,4 +35,9 @@ void construct_in_place(uninit_t<T>& buf, Args... args) {
}
} // namespace support
template <class T>
inline static T* maybe_local_ptr(v8::MaybeLocal<T> value) {
return *value.FromMaybe(v8::Local<T>());
}
#endif // SUPPORT_H_

View file

@ -6,6 +6,7 @@ use std::ops::Deref;
use std::ops::DerefMut;
use std::ptr::NonNull;
pub use std::os::raw::c_char as char;
pub use std::os::raw::c_int as int;
pub type Opaque = [usize; 0];

View file

@ -76,6 +76,24 @@ fn handle_scope_numbers() {
drop(g);
}
#[test]
fn test_string() {
setup();
let mut params = v8::Isolate::create_params();
params.set_array_buffer_allocator(
v8::array_buffer::Allocator::new_default_allocator(),
);
let mut isolate = v8::Isolate::new(params);
let mut locker = v8::Locker::new(&mut isolate);
v8::HandleScope::enter(&mut locker, |scope| {
let reference = "Hello 🦕 world!";
let local =
v8::String::new(scope, reference, v8::string::NewStringType::Normal)
.unwrap();
assert_eq!(reference, local.to_rust_string_lossy(scope));
});
}
#[test]
fn isolate_new() {
let g = setup();