0
0
Fork 0
mirror of https://github.com/denoland/rusty_v8.git synced 2025-01-23 07:29:56 -05:00

Support for external v8 strings (#641)

This commit is contained in:
Aaron O'Mullan 2021-03-07 16:21:59 +01:00 committed by GitHub
parent a6d36d1193
commit f2766ed1af
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 126 additions and 0 deletions

View file

@ -832,6 +832,32 @@ int v8__String__WriteUtf8(const v8::String& self, v8::Isolate* isolate,
return self.WriteUtf8(isolate, buffer, length, nchars_ref, options); return self.WriteUtf8(isolate, buffer, length, nchars_ref, options);
} }
class ExternalStaticOneByteStringResource: public v8::String::ExternalOneByteStringResource {
public:
ExternalStaticOneByteStringResource(const char *data, int length):
_data(data), _length(length) {}
const char* data() const override { return _data; }
size_t length() const override { return _length; }
private:
const char* _data;
const int _length;
};
const v8::String* v8__String__NewExternalOneByteStatic(v8::Isolate *isolate,
const char *data, int length) {
return maybe_local_to_ptr(
v8::String::NewExternalOneByte(
isolate, new ExternalStaticOneByteStringResource(data, length)
)
);
}
bool v8__String__IsExternal(const v8::String& self) { return self.IsExternal(); }
bool v8__String__IsExternalOneByte(const v8::String& self) { return self.IsExternalOneByte(); }
bool v8__String__IsExternalTwoByte(const v8::String& self) { return self.IsExternalTwoByte(); }
bool v8__String__IsOneByte(const v8::String& self) { return self.IsOneByte(); }
const v8::Symbol* v8__Symbol__New(v8::Isolate* isolate, const v8::Symbol* v8__Symbol__New(v8::Isolate* isolate,
const v8::String& description) { const v8::String& description) {
return local_to_ptr(v8::Symbol::New(isolate, ptr_to_local(&description))); return local_to_ptr(v8::Symbol::New(isolate, ptr_to_local(&description)));

View file

@ -32,6 +32,17 @@ extern "C" {
nchars_ref: *mut int, nchars_ref: *mut int,
options: WriteOptions, options: WriteOptions,
) -> int; ) -> int;
fn v8__String__NewExternalOneByteStatic(
isolate: *mut Isolate,
buffer: *const char,
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;
} }
#[repr(C)] #[repr(C)]
@ -134,6 +145,57 @@ impl String {
Self::new_from_utf8(scope, value.as_ref(), NewStringType::Normal) Self::new_from_utf8(scope, value.as_ref(), NewStringType::Normal)
} }
// Creates a v8::String from a `&'static str`,
// must be Latin-1 or ASCII, not UTF-8 !
pub fn new_external_onebyte_static<'s>(
scope: &mut HandleScope<'s, ()>,
value: &'static str,
) -> Option<Local<'s, String>> {
let buffer: &[u8] = value.as_ref();
if buffer.is_empty() {
return None;
}
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,
)
})
}
}
/// True if string is external
pub fn is_external(&self) -> bool {
// TODO: re-enable on next v8-release
// Right now it fallbacks to Value::IsExternal, which is incorrect
// See: https://source.chromium.org/chromium/_/chromium/v8/v8.git/+/1dd8624b524d14076160c1743f7da0b20fbe68e0
// unsafe { v8__String__IsExternal(self) }
// Fallback for now (though functionally identical)
self.is_external_onebyte() || self.is_external_twobyte()
}
/// True if string is external & one-byte
/// (e.g: created with new_external_onebyte_static)
pub fn is_external_onebyte(&self) -> bool {
unsafe { v8__String__IsExternalOneByte(self) }
}
/// True if string is external & two-byte
/// NOTE: can't yet be created via rusty_v8
pub fn is_external_twobyte(&self) -> bool {
unsafe { v8__String__IsExternalTwoByte(self) }
}
/// True if string is known to contain only one-byte data
/// doesn't read the string so can return false positives
pub fn is_onebyte(&self) -> bool {
unsafe { v8__String__IsExternalOneByte(self) }
}
/// Convenience function not present in the original V8 API. /// Convenience function not present in the original V8 API.
pub fn to_rust_string_lossy( pub fn to_rust_string_lossy(
&self, &self,

View file

@ -4959,3 +4959,41 @@ fn code_cache_script() {
let ret = script.run(scope).unwrap(); let ret = script.run(scope).unwrap();
assert_eq!(ret.uint32_value(scope).unwrap(), 2); assert_eq!(ret.uint32_value(scope).unwrap(), 2);
} }
#[test]
fn external_strings() {
let _setup_guard = setup();
let isolate = &mut v8::Isolate::new(Default::default());
let scope = &mut v8::HandleScope::new(isolate);
let context = v8::Context::new(scope);
let scope = &mut v8::ContextScope::new(scope, context);
// Parse JSON from an external string
let json_static = "{\"a\": 1, \"b\": 2}";
let json_external =
v8::String::new_external_onebyte_static(scope, json_static).unwrap();
let maybe_value = v8::json::parse(scope, json_external);
assert!(maybe_value.is_some());
// Check length
assert!(json_external.length() == 16);
// Externality checks
assert!(json_external.is_external());
assert!(json_external.is_external_onebyte());
assert!(json_external.is_onebyte());
// In & out
let hello =
v8::String::new_external_onebyte_static(scope, "hello world").unwrap();
let rust_str = hello.to_rust_string_lossy(scope);
assert_eq!(rust_str, "hello world");
// Externality checks
assert!(hello.is_external());
assert!(hello.is_external_onebyte());
assert!(hello.is_onebyte());
// two-byte "internal" test
let gradients = v8::String::new(scope, "∇gradients").unwrap();
assert!(!gradients.is_external());
assert!(!gradients.is_external_onebyte());
assert!(!gradients.is_onebyte());
}