0
0
Fork 0
mirror of https://github.com/denoland/rusty_v8.git synced 2025-03-08 20:16:41 -05:00

add Symbol, Private, BigInt (#466)

This commit is contained in:
devsnek 2020-09-29 19:20:07 -05:00 committed by GitHub
parent 6b90cbe499
commit e5f56e218c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 477 additions and 2 deletions

135
src/bigint.rs Normal file
View file

@ -0,0 +1,135 @@
use crate::support::int;
use crate::BigInt;
use crate::Context;
use crate::HandleScope;
use crate::Isolate;
use crate::Local;
use std::mem::MaybeUninit;
extern "C" {
fn v8__BigInt__New(isolate: *mut Isolate, value: i64) -> *const BigInt;
fn v8__BigInt__NewFromUnsigned(
isolate: *mut Isolate,
value: u64,
) -> *const BigInt;
fn v8__BigInt__NewFromWords(
context: *const Context,
sign_bit: int,
word_count: int,
words: *const u64,
) -> *const BigInt;
fn v8__BigInt__Uint64Value(this: *const BigInt, lossless: *mut bool) -> u64;
fn v8__BigInt__Int64Value(this: *const BigInt, lossless: *mut bool) -> i64;
fn v8__BigInt__WordCount(this: *const BigInt) -> int;
fn v8__BigInt__ToWordsArray(
this: *const BigInt,
sign_bit: *mut int,
word_count: *mut int,
words: *mut u64,
);
}
impl BigInt {
pub fn new_from_i64<'s>(
scope: &mut HandleScope<'s>,
value: i64,
) -> Local<'s, BigInt> {
unsafe {
scope.cast_local(|sd| v8__BigInt__New(sd.get_isolate_ptr(), value))
}
.unwrap()
}
pub fn new_from_u64<'s>(
scope: &mut HandleScope<'s>,
value: u64,
) -> Local<'s, BigInt> {
unsafe {
scope.cast_local(|sd| {
v8__BigInt__NewFromUnsigned(sd.get_isolate_ptr(), value)
})
}
.unwrap()
}
/// Creates a new BigInt object using a specified sign bit and a
/// specified list of digits/words.
/// The resulting number is calculated as:
///
/// (-1)^sign_bit * (words[0] * (2^64)^0 + words[1] * (2^64)^1 + ...)
pub fn new_from_words<'s>(
scope: &mut HandleScope<'s>,
sign_bit: bool,
words: &[u64],
) -> Option<Local<'s, BigInt>> {
unsafe {
scope.cast_local(|sd| {
v8__BigInt__NewFromWords(
sd.get_current_context(),
sign_bit as int,
words.len() as int,
words.as_ptr(),
)
})
}
}
/// Returns the value of this BigInt as an unsigned 64-bit integer, and a
/// `bool` indicating whether the return value was truncated was truncated or
/// wrapped around. In particular, it will be `false` if this BigInt is
/// negative.
pub fn u64_value(&self) -> (u64, bool) {
let mut lossless = MaybeUninit::uninit();
let v = unsafe { v8__BigInt__Uint64Value(&*self, lossless.as_mut_ptr()) };
let lossless = unsafe { lossless.assume_init() };
(v, lossless)
}
/// Returns the value of this BigInt as a signed 64-bit integer, and a `bool`
/// indicating whether this BigInt was truncated or not.
pub fn i64_value(&self) -> (i64, bool) {
let mut lossless = MaybeUninit::uninit();
let v = unsafe { v8__BigInt__Int64Value(&*self, lossless.as_mut_ptr()) };
let lossless = unsafe { lossless.assume_init() };
(v, lossless)
}
/// Returns the number of 64-bit words needed to store the result of
/// `to_words_array`.
pub fn word_count(&self) -> usize {
unsafe { v8__BigInt__WordCount(&*self) as usize }
}
/// Converts this BigInt to a (sign_bit, words) pair. `sign_bit` will be true
/// if this BigInt is negative. If `words` has too few elements, the result will
/// be truncated to fit.
pub fn to_words_array<'a>(
&self,
words: &'a mut [u64],
) -> (bool, &'a mut [u64]) {
let mut sign_bit = MaybeUninit::uninit();
let mut word_count = words.len() as int;
unsafe {
v8__BigInt__ToWordsArray(
&*self,
sign_bit.as_mut_ptr(),
&mut word_count,
words.as_mut_ptr(),
)
}
let sign_bit = unsafe { sign_bit.assume_init() };
debug_assert!(sign_bit == 0 || sign_bit == 1);
let word_count = word_count as usize;
(
sign_bit == 1,
if word_count < words.len() {
&mut words[..word_count]
} else {
words
},
)
}
}

View file

@ -717,6 +717,57 @@ int v8__String__WriteUtf8(const v8::String& self, v8::Isolate* isolate,
return self.WriteUtf8(isolate, buffer, length, nchars_ref, options);
}
const v8::Symbol* v8__Symbol__New(v8::Isolate* isolate,
const v8::String* description) {
return local_to_ptr(v8::Symbol::New(isolate, ptr_to_local(description)));
}
const v8::Symbol* v8__Symbol__For(v8::Isolate* isolate,
const v8::String* description) {
return local_to_ptr(v8::Symbol::For(isolate, ptr_to_local(description)));
}
const v8::Symbol* v8__Symbol__ForApi(v8::Isolate* isolate,
const v8::String* description) {
return local_to_ptr(v8::Symbol::ForApi(isolate, ptr_to_local(description)));
}
#define V(NAME) \
const v8::Symbol* v8__Symbol__Get##NAME(v8::Isolate* isolate) { \
return local_to_ptr(v8::Symbol::Get##NAME(isolate)); \
}
V(AsyncIterator)
V(HasInstance)
V(IsConcatSpreadable)
V(Iterator)
V(Match)
V(Replace)
V(Search)
V(Split)
V(ToPrimitive)
V(ToStringTag)
V(Unscopables)
#undef V
const v8::Value* v8__Symbol__Description(const v8::Symbol& self) {
return local_to_ptr(ptr_to_local(&self)->Description());
}
const v8::Private* v8__Private__New(v8::Isolate* isolate,
const v8::String* name) {
return local_to_ptr(v8::Private::New(isolate, ptr_to_local(name)));
}
const v8::Private* v8__Private__ForApi(v8::Isolate* isolate,
const v8::String* name) {
return local_to_ptr(v8::Private::ForApi(isolate, ptr_to_local(name)));
}
const v8::Value* v8__Private__Name(const v8::Private& self) {
return local_to_ptr(ptr_to_local(&self)->Name());
}
void v8__Template__Set(const v8::Template& self, const v8::Name& key,
const v8::Data& value, v8::PropertyAttribute attr) {
ptr_to_local(&self)->Set(ptr_to_local(&key), ptr_to_local(&value), attr);
@ -948,6 +999,39 @@ const v8::Integer* v8__Integer__NewFromUnsigned(v8::Isolate* isolate,
int64_t v8__Integer__Value(const v8::Integer& self) { return self.Value(); }
const v8::BigInt* v8__BigInt__New(v8::Isolate* isolate, int64_t value) {
return local_to_ptr(v8::BigInt::New(isolate, value));
}
const v8::BigInt* v8__BigInt__NewFromUnsigned(v8::Isolate* isolate,
uint64_t value) {
return local_to_ptr(v8::BigInt::NewFromUnsigned(isolate, value));
}
const v8::BigInt* v8__BigInt__NewFromWords(const v8::Context& context,
int sign_bit, int word_count,
const uint64_t* words) {
return maybe_local_to_ptr(v8::BigInt::NewFromWords(
ptr_to_local(&context), sign_bit, word_count, words));
}
uint64_t v8__BigInt__Uint64Value(const v8::BigInt& self, bool* lossless) {
return ptr_to_local(&self)->Uint64Value(lossless);
}
int64_t v8__BigInt__Int64Value(const v8::BigInt& self, bool* lossless) {
return ptr_to_local(&self)->Int64Value(lossless);
}
int v8__BigInt__WordCount(const v8::BigInt& self) {
return ptr_to_local(&self)->WordCount();
}
void v8__BigInt__ToWordsArray(const v8::BigInt& self, int* sign_bit,
int* word_count, uint64_t* words) {
ptr_to_local(&self)->ToWordsArray(sign_bit, word_count, words);
}
const v8::ArrayBuffer* v8__ArrayBufferView__Buffer(
const v8::ArrayBufferView& self) {
return local_to_ptr(ptr_to_local(&self)->Buffer());

View file

@ -35,6 +35,7 @@ extern crate libc;
mod array_buffer;
mod array_buffer_view;
mod bigint;
mod context;
mod data;
mod date;
@ -52,6 +53,7 @@ mod object;
mod platform;
mod primitive_array;
mod primitives;
mod private;
mod promise;
mod property_attribute;
mod proxy;
@ -62,6 +64,7 @@ mod shared_array_buffer;
mod snapshot;
mod string;
mod support;
mod symbol;
mod template;
mod uint8_array;
mod value;
@ -75,6 +78,7 @@ pub mod script_compiler;
pub mod V8;
pub use array_buffer::*;
pub use bigint::*;
pub use data::*;
pub use exception::*;
pub use external_references::ExternalReference;
@ -103,6 +107,7 @@ pub use platform::Task;
pub use platform::TaskBase;
pub use platform::TaskImpl;
pub use primitives::*;
pub use private::*;
pub use promise::{PromiseRejectEvent, PromiseRejectMessage, PromiseState};
pub use property_attribute::*;
pub use proxy::*;
@ -120,6 +125,7 @@ pub use support::SharedPtr;
pub use support::SharedRef;
pub use support::UniquePtr;
pub use support::UniqueRef;
pub use symbol::*;
pub use template::*;
// TODO(piscisaureus): Ideally this trait would not be exported.

63
src/private.rs Normal file
View file

@ -0,0 +1,63 @@
use crate::HandleScope;
use crate::Isolate;
use crate::Local;
use crate::Private;
use crate::String;
use crate::Value;
extern "C" {
fn v8__Private__New(
isolate: *mut Isolate,
name: *const String,
) -> *const Private;
fn v8__Private__ForApi(
isolate: *mut Isolate,
name: *const String,
) -> *const Private;
fn v8__Private__Name(this: *const Private) -> *const Value;
}
impl Private {
/// Create a private symbol. If name is not empty, it will be the description.
pub fn new<'s>(
scope: &mut HandleScope<'s>,
name: Option<Local<String>>,
) -> Local<'s, Private> {
unsafe {
scope.cast_local(|sd| {
v8__Private__New(
sd.get_isolate_ptr(),
name.map_or_else(std::ptr::null, |v| &*v),
)
})
}
.unwrap()
}
/// Retrieve a global private symbol. If a symbol with this name has not
/// been retrieved in the same isolate before, it is created.
/// Note that private symbols created this way are never collected, so
/// they should only be used for statically fixed properties.
/// Also, there is only one global name space for the names used as keys.
/// To minimize the potential for clashes, use qualified names as keys,
/// e.g., "Class#property".
pub fn for_api<'s>(
scope: &mut HandleScope<'s>,
name: Option<Local<String>>,
) -> Local<'s, Private> {
unsafe {
scope.cast_local(|sd| {
v8__Private__ForApi(
sd.get_isolate_ptr(),
name.map_or_else(std::ptr::null, |v| &*v),
)
})
}
.unwrap()
}
/// Returns the print name string of the private symbol, or undefined if none.
pub fn name<'s>(&self, scope: &mut HandleScope<'s>) -> Local<'s, Value> {
unsafe { scope.cast_local(|_| v8__Private__Name(&*self)) }.unwrap()
}
}

87
src/symbol.rs Normal file
View file

@ -0,0 +1,87 @@
use crate::HandleScope;
use crate::Isolate;
use crate::Local;
use crate::String;
use crate::Symbol;
use crate::Value;
extern "C" {
fn v8__Symbol__New(
isolate: *mut Isolate,
description: *const String,
) -> *const Symbol;
fn v8__Symbol__ForApi(
isolate: *mut Isolate,
description: *const String,
) -> *const Symbol;
fn v8__Symbol__Description(this: *const Symbol) -> *const Value;
}
macro_rules! well_known {
($name:ident, $binding:ident) => {
pub fn $name<'s>(scope: &mut HandleScope<'s>) -> Local<'s, Symbol> {
extern "C" {
fn $binding(isolate: *mut Isolate) -> *const Symbol;
}
unsafe { scope.cast_local(|sd| $binding(sd.get_isolate_ptr())) }.unwrap()
}
};
}
impl Symbol {
/// Create a symbol. If description is not empty, it will be used as the
/// description.
pub fn new<'s>(
scope: &mut HandleScope<'s>,
description: Option<Local<String>>,
) -> Local<'s, Symbol> {
unsafe {
scope.cast_local(|sd| {
v8__Symbol__New(
sd.get_isolate_ptr(),
description.map_or_else(std::ptr::null, |v| &*v),
)
})
}
.unwrap()
}
/// Access global symbol registry.
/// Note that symbols created this way are never collected, so
/// they should only be used for statically fixed properties.
/// Also, there is only one global description space for the descriptions used as
/// keys.
/// To minimize the potential for clashes, use qualified descriptions as keys.
/// Corresponds to v8::Symbol::For() in C++.
pub fn for_global<'s>(
scope: &mut HandleScope<'s>,
description: Local<String>,
) -> Local<'s, Symbol> {
unsafe {
scope.cast_local(|sd| {
v8__Symbol__ForApi(sd.get_isolate_ptr(), &*description)
})
}
.unwrap()
}
/// Returns the description string of the symbol, or undefined if none.
pub fn description<'s>(
&self,
scope: &mut HandleScope<'s>,
) -> Local<'s, Value> {
unsafe { scope.cast_local(|_| v8__Symbol__Description(&*self)) }.unwrap()
}
well_known!(get_async_iterator, v8__Symbol__GetAsyncIterator);
well_known!(get_has_instance, v8__Symbol__GetHasInstance);
well_known!(get_is_concat_spreadable, v8__Symbol__GetIsConcatSpreadable);
well_known!(get_iterator, v8__Symbol__GetIterator);
well_known!(get_match, v8__Symbol__GetMatch);
well_known!(get_replace, v8__Symbol__GetReplace);
well_known!(get_search, v8__Symbol__GetSearch);
well_known!(get_split, v8__Symbol__GetSplit);
well_known!(get_to_primitive, v8__Symbol__GetToPrimitive);
well_known!(get_to_string_tag, v8__Symbol__GetToStringTag);
well_known!(get_unscopables, v8__Symbol__GetUnscopables);
}

View file

@ -2810,16 +2810,22 @@ fn try_from_data() {
v8::Local::<v8::ObjectTemplate>::try_from(d).unwrap() == object_template
);
// There is currently no way to construct instances of `v8::Private`,
// therefore we don't have a test where `is_private()` succeeds.
let p: v8::Local<v8::Data> = v8::Private::new(scope, None).into();
assert!(!p.is_function_template());
assert!(!p.is_module());
assert!(!p.is_object_template());
assert!(p.is_private());
assert!(!p.is_value());
let values: &[v8::Local<v8::Value>] = &[
v8::null(scope).into(),
v8::undefined(scope).into(),
v8::BigInt::new_from_u64(scope, 1337).into(),
v8::Boolean::new(scope, true).into(),
v8::Function::new(scope, function_callback).unwrap().into(),
v8::Number::new(scope, 42.0).into(),
v8::Object::new(scope).into(),
v8::Symbol::new(scope, None).into(),
v8::String::new(scope, "hello").unwrap().into(),
];
for &v in values {
@ -3644,3 +3650,97 @@ fn date() {
assert_eq!(date.value_of(), 3.0);
assert_eq!(date.number_value(scope).unwrap(), 3.0);
}
#[test]
fn symbol() {
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);
let desc = v8::String::new(scope, "a description").unwrap();
let s = v8::Symbol::new(scope, None);
assert!(s.description(scope) == v8::undefined(scope));
let s = v8::Symbol::new(scope, Some(desc));
assert!(s.description(scope) == desc);
let s_pub = v8::Symbol::for_global(scope, desc);
assert!(s_pub.description(scope) == desc);
assert!(s_pub != s);
let s_pub2 = v8::Symbol::for_global(scope, desc);
assert!(s_pub2 != s);
assert!(s_pub == s_pub2);
let s = eval(scope, "Symbol.asyncIterator").unwrap();
assert!(s == v8::Symbol::get_async_iterator(scope));
}
#[test]
fn private() {
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);
let p = v8::Private::new(scope, None);
assert!(p.name(scope) == v8::undefined(scope));
let name = v8::String::new(scope, "a name").unwrap();
let p = v8::Private::new(scope, Some(name));
assert!(p.name(scope) == name);
let p_api = v8::Private::for_api(scope, Some(name));
assert!(p_api.name(scope) == name);
assert!(p_api != p);
let p_api2 = v8::Private::for_api(scope, Some(name));
assert!(p_api2 != p);
assert!(p_api == p_api2);
}
#[test]
fn bigint() {
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);
let b = v8::BigInt::new_from_u64(scope, 1337);
assert_eq!(b.u64_value(), (1337, true));
let b = v8::BigInt::new_from_i64(scope, -1337);
assert_eq!(b.i64_value(), (-1337, true));
let words = vec![10, 10];
let b = v8::BigInt::new_from_words(scope, false, &words).unwrap();
assert_eq!(b.i64_value(), (10, false));
let raw_b = eval(scope, "184467440737095516170n").unwrap();
assert!(b == raw_b);
let b = v8::BigInt::new_from_words(scope, true, &words).unwrap();
assert_eq!(b.i64_value(), (-10, false));
let raw_b = eval(scope, "-184467440737095516170n").unwrap();
assert!(b == raw_b);
let raw_b = v8::Local::<v8::BigInt>::try_from(raw_b).unwrap();
let mut vec = Vec::new();
vec.resize(raw_b.word_count(), 0);
assert_eq!(raw_b.to_words_array(&mut vec), (true, &mut [10, 10][..]));
let mut vec = Vec::new();
vec.resize(1, 0);
assert_eq!(raw_b.to_words_array(&mut vec), (true, &mut [10][..]));
let mut vec = Vec::new();
vec.resize(20, 1337);
assert_eq!(raw_b.to_words_array(&mut vec), (true, &mut [10, 10][..]));
}