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:
parent
a6d36d1193
commit
f2766ed1af
3 changed files with 126 additions and 0 deletions
|
@ -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)));
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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());
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue