2020-01-17 03:56:34 +01:00
|
|
|
use std::convert::TryFrom;
|
2019-12-21 06:08:00 +01:00
|
|
|
use std::marker::PhantomData;
|
|
|
|
|
2020-01-04 15:23:36 +01:00
|
|
|
use crate::support::MapFnFrom;
|
|
|
|
use crate::support::MapFnTo;
|
|
|
|
use crate::support::ToCFn;
|
|
|
|
use crate::support::UnitType;
|
2019-12-11 04:43:22 +01:00
|
|
|
use crate::support::{int, Opaque};
|
2020-06-03 07:38:34 +02:00
|
|
|
use crate::CallbackScope;
|
2019-12-11 04:43:22 +01:00
|
|
|
use crate::Context;
|
2019-12-30 15:28:39 +01:00
|
|
|
use crate::Function;
|
2020-06-03 07:38:34 +02:00
|
|
|
use crate::HandleScope;
|
2019-12-11 04:43:22 +01:00
|
|
|
use crate::Local;
|
2020-01-04 15:23:36 +01:00
|
|
|
use crate::Name;
|
|
|
|
use crate::Object;
|
2019-12-11 04:43:22 +01:00
|
|
|
use crate::Value;
|
|
|
|
|
|
|
|
extern "C" {
|
|
|
|
fn v8__Function__New(
|
2020-04-13 14:43:56 +02:00
|
|
|
context: *const Context,
|
2019-12-27 09:12:16 -05:00
|
|
|
callback: FunctionCallback,
|
2020-04-13 14:43:56 +02:00
|
|
|
) -> *const Function;
|
2020-03-14 19:42:18 -07:00
|
|
|
fn v8__Function__NewWithData(
|
2020-04-13 14:43:56 +02:00
|
|
|
context: *const Context,
|
2020-03-14 19:42:18 -07:00
|
|
|
callback: FunctionCallback,
|
2020-04-13 14:43:56 +02:00
|
|
|
data: *const Value,
|
|
|
|
) -> *const Function;
|
2019-12-11 04:43:22 +01:00
|
|
|
fn v8__Function__Call(
|
2020-04-13 14:43:56 +02:00
|
|
|
this: *const Function,
|
|
|
|
context: *const Context,
|
|
|
|
recv: *const Value,
|
2019-12-11 04:43:22 +01:00
|
|
|
argc: int,
|
2020-04-13 14:43:56 +02:00
|
|
|
argv: *const *const Value,
|
|
|
|
) -> *const Value;
|
2019-12-11 04:43:22 +01:00
|
|
|
|
2019-12-14 23:14:09 +01:00
|
|
|
fn v8__FunctionCallbackInfo__GetReturnValue(
|
2020-01-04 15:23:36 +01:00
|
|
|
info: *const FunctionCallbackInfo,
|
|
|
|
) -> *mut Value;
|
|
|
|
fn v8__FunctionCallbackInfo__This(
|
2020-04-13 14:43:56 +02:00
|
|
|
this: *const FunctionCallbackInfo,
|
|
|
|
) -> *const Object;
|
|
|
|
fn v8__FunctionCallbackInfo__Length(this: *const FunctionCallbackInfo)
|
2020-01-04 15:23:36 +01:00
|
|
|
-> int;
|
2019-12-30 22:48:23 +01:00
|
|
|
fn v8__FunctionCallbackInfo__GetArgument(
|
2020-04-13 14:43:56 +02:00
|
|
|
this: *const FunctionCallbackInfo,
|
2019-12-30 22:48:23 +01:00
|
|
|
i: int,
|
2020-04-13 14:43:56 +02:00
|
|
|
) -> *const Value;
|
2020-03-14 19:42:18 -07:00
|
|
|
fn v8__FunctionCallbackInfo__Data(
|
2020-04-13 14:43:56 +02:00
|
|
|
this: *const FunctionCallbackInfo,
|
|
|
|
) -> *const Value;
|
2019-12-17 19:19:40 +01:00
|
|
|
|
2020-01-04 15:23:36 +01:00
|
|
|
fn v8__PropertyCallbackInfo__GetReturnValue(
|
2020-04-13 14:43:56 +02:00
|
|
|
this: *const PropertyCallbackInfo,
|
2020-01-04 15:23:36 +01:00
|
|
|
) -> *mut Value;
|
|
|
|
fn v8__PropertyCallbackInfo__This(
|
2020-04-13 14:43:56 +02:00
|
|
|
this: *const PropertyCallbackInfo,
|
|
|
|
) -> *const Object;
|
2020-01-04 15:23:36 +01:00
|
|
|
|
2020-04-13 14:43:56 +02:00
|
|
|
fn v8__ReturnValue__Set(this: *mut ReturnValue, value: *const Value);
|
|
|
|
fn v8__ReturnValue__Get(this: *const ReturnValue) -> *const Value;
|
2019-12-14 23:14:09 +01:00
|
|
|
}
|
|
|
|
|
2019-12-21 06:08:00 +01:00
|
|
|
// Npte: the 'cb lifetime is required because the ReturnValue object must not
|
|
|
|
// outlive the FunctionCallbackInfo/PropertyCallbackInfo object from which it
|
|
|
|
// is derived.
|
2019-12-14 23:14:09 +01:00
|
|
|
#[repr(C)]
|
2020-01-04 15:23:36 +01:00
|
|
|
pub struct ReturnValue<'cb>(*mut Value, PhantomData<&'cb ()>);
|
2019-12-14 23:14:09 +01:00
|
|
|
|
2019-12-17 19:19:40 +01:00
|
|
|
/// In V8 ReturnValue<> has a type parameter, but
|
|
|
|
/// it turns out that in most of the APIs it's ReturnValue<Value>
|
|
|
|
/// and for our purposes we currently don't need
|
|
|
|
/// other types. So for now it's a simplified version.
|
2019-12-21 06:08:00 +01:00
|
|
|
impl<'cb> ReturnValue<'cb> {
|
2020-01-04 15:23:36 +01:00
|
|
|
fn from_function_callback_info(info: *const FunctionCallbackInfo) -> Self {
|
|
|
|
let slot = unsafe { v8__FunctionCallbackInfo__GetReturnValue(info) };
|
|
|
|
Self(slot, PhantomData)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn from_property_callback_info(info: *const PropertyCallbackInfo) -> Self {
|
|
|
|
let slot = unsafe { v8__PropertyCallbackInfo__GetReturnValue(info) };
|
|
|
|
Self(slot, PhantomData)
|
|
|
|
}
|
|
|
|
|
2019-12-14 23:14:09 +01:00
|
|
|
// NOTE: simplest setter, possibly we'll need to add
|
|
|
|
// more setters specialized per type
|
2020-04-13 14:43:56 +02:00
|
|
|
pub fn set(&mut self, value: Local<Value>) {
|
|
|
|
unsafe { v8__ReturnValue__Set(&mut *self, &*value) }
|
2019-12-14 23:14:09 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Getter. Creates a new Local<> so it comes with a certain performance
|
|
|
|
/// hit. If the ReturnValue was not yet set, this will return the undefined
|
|
|
|
/// value.
|
2020-06-26 14:47:13 +02:00
|
|
|
pub fn get<'s>(&self, scope: &mut HandleScope<'s>) -> Local<'s, Value> {
|
2020-05-31 15:00:23 +02:00
|
|
|
unsafe { scope.cast_local(|_| v8__ReturnValue__Get(self)) }.unwrap()
|
2019-12-14 23:14:09 +01:00
|
|
|
}
|
2019-12-11 04:43:22 +01:00
|
|
|
}
|
|
|
|
|
2019-12-19 14:14:19 +01:00
|
|
|
/// The argument information given to function call callbacks. This
|
|
|
|
/// class provides access to information about the context of the call,
|
|
|
|
/// including the receiver, the number and values of arguments, and
|
|
|
|
/// the holder of the function.
|
2019-12-11 04:43:22 +01:00
|
|
|
#[repr(C)]
|
2020-01-04 15:23:36 +01:00
|
|
|
pub struct FunctionCallbackInfo {
|
|
|
|
// The layout of this struct must match that of `class FunctionCallbackInfo`
|
|
|
|
// as defined in v8.h.
|
|
|
|
implicit_args: *mut Opaque,
|
2020-04-13 14:43:56 +02:00
|
|
|
values: *const Value,
|
2020-01-04 15:23:36 +01:00
|
|
|
length: int,
|
|
|
|
}
|
2019-12-11 04:43:22 +01:00
|
|
|
|
2020-01-04 15:23:36 +01:00
|
|
|
/// The information passed to a property callback about the context
|
|
|
|
/// of the property access.
|
|
|
|
#[repr(C)]
|
|
|
|
pub struct PropertyCallbackInfo {
|
|
|
|
// The layout of this struct must match that of `class PropertyCallbackInfo`
|
|
|
|
// as defined in v8.h.
|
|
|
|
args: *mut Opaque,
|
2019-12-25 00:31:36 +01:00
|
|
|
}
|
|
|
|
|
2020-01-04 15:23:36 +01:00
|
|
|
pub struct FunctionCallbackArguments<'s> {
|
|
|
|
info: *const FunctionCallbackInfo,
|
|
|
|
phantom: PhantomData<&'s ()>,
|
|
|
|
}
|
2019-12-25 00:31:36 +01:00
|
|
|
|
2020-01-04 15:23:36 +01:00
|
|
|
impl<'s> FunctionCallbackArguments<'s> {
|
|
|
|
fn from_function_callback_info(info: *const FunctionCallbackInfo) -> Self {
|
|
|
|
Self {
|
|
|
|
info,
|
|
|
|
phantom: PhantomData,
|
2019-12-20 18:16:44 +01:00
|
|
|
}
|
2019-12-14 23:14:09 +01:00
|
|
|
}
|
|
|
|
|
2020-01-04 15:23:36 +01:00
|
|
|
/// Returns the receiver. This corresponds to the "this" value.
|
2020-05-31 13:39:00 +02:00
|
|
|
pub fn this(&self) -> Local<'s, Object> {
|
2020-01-04 15:23:36 +01:00
|
|
|
unsafe {
|
|
|
|
Local::from_raw(v8__FunctionCallbackInfo__This(self.info)).unwrap()
|
|
|
|
}
|
2019-12-11 04:43:22 +01:00
|
|
|
}
|
|
|
|
|
2020-03-14 19:42:18 -07:00
|
|
|
/// Returns the data argument specified when creating the callback.
|
2020-05-31 13:39:00 +02:00
|
|
|
pub fn data(&self) -> Option<Local<'s, Value>> {
|
2020-03-14 19:42:18 -07:00
|
|
|
unsafe { Local::from_raw(v8__FunctionCallbackInfo__Data(self.info)) }
|
|
|
|
}
|
|
|
|
|
2019-12-19 14:14:19 +01:00
|
|
|
/// The number of available arguments.
|
2019-12-11 04:43:22 +01:00
|
|
|
pub fn length(&self) -> int {
|
2020-01-04 15:23:36 +01:00
|
|
|
unsafe {
|
|
|
|
let length = (*self.info).length;
|
|
|
|
debug_assert_eq!(length, v8__FunctionCallbackInfo__Length(self.info));
|
|
|
|
length
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Accessor for the available arguments. Returns `undefined` if the index is
|
|
|
|
/// out of bounds.
|
2020-05-31 13:39:00 +02:00
|
|
|
pub fn get(&self, i: int) -> Local<'s, Value> {
|
2020-01-04 15:23:36 +01:00
|
|
|
unsafe {
|
|
|
|
Local::from_raw(v8__FunctionCallbackInfo__GetArgument(self.info, i))
|
|
|
|
.unwrap()
|
|
|
|
}
|
2019-12-11 04:43:22 +01:00
|
|
|
}
|
2020-01-04 15:23:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
pub struct PropertyCallbackArguments<'s> {
|
|
|
|
info: *const PropertyCallbackInfo,
|
|
|
|
phantom: PhantomData<&'s ()>,
|
|
|
|
}
|
2019-12-30 22:48:23 +01:00
|
|
|
|
2020-01-04 15:23:36 +01:00
|
|
|
impl<'s> PropertyCallbackArguments<'s> {
|
|
|
|
fn from_property_callback_info(info: *const PropertyCallbackInfo) -> Self {
|
|
|
|
Self {
|
|
|
|
info,
|
|
|
|
phantom: PhantomData,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the receiver. In many cases, this is the object on which the
|
|
|
|
/// property access was intercepted. When using
|
|
|
|
/// `Reflect.get`, `Function.prototype.call`, or similar functions, it is the
|
|
|
|
/// object passed in as receiver or thisArg.
|
|
|
|
///
|
|
|
|
/// ```c++
|
|
|
|
/// void GetterCallback(Local<Name> name,
|
|
|
|
/// const v8::PropertyCallbackInfo<v8::Value>& info) {
|
|
|
|
/// auto context = info.GetIsolate()->GetCurrentContext();
|
|
|
|
///
|
|
|
|
/// v8::Local<v8::Value> a_this =
|
|
|
|
/// info.This()
|
|
|
|
/// ->GetRealNamedProperty(context, v8_str("a"))
|
|
|
|
/// .ToLocalChecked();
|
|
|
|
/// v8::Local<v8::Value> a_holder =
|
|
|
|
/// info.Holder()
|
|
|
|
/// ->GetRealNamedProperty(context, v8_str("a"))
|
|
|
|
/// .ToLocalChecked();
|
|
|
|
///
|
|
|
|
/// CHECK(v8_str("r")->Equals(context, a_this).FromJust());
|
|
|
|
/// CHECK(v8_str("obj")->Equals(context, a_holder).FromJust());
|
|
|
|
///
|
|
|
|
/// info.GetReturnValue().Set(name);
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// v8::Local<v8::FunctionTemplate> templ =
|
|
|
|
/// v8::FunctionTemplate::New(isolate);
|
|
|
|
/// templ->InstanceTemplate()->SetHandler(
|
|
|
|
/// v8::NamedPropertyHandlerConfiguration(GetterCallback));
|
|
|
|
/// LocalContext env;
|
|
|
|
/// env->Global()
|
|
|
|
/// ->Set(env.local(), v8_str("obj"), templ->GetFunction(env.local())
|
|
|
|
/// .ToLocalChecked()
|
|
|
|
/// ->NewInstance(env.local())
|
|
|
|
/// .ToLocalChecked())
|
|
|
|
/// .FromJust();
|
|
|
|
///
|
|
|
|
/// CompileRun("obj.a = 'obj'; var r = {a: 'r'}; Reflect.get(obj, 'x', r)");
|
|
|
|
/// ```
|
2020-05-31 13:39:00 +02:00
|
|
|
pub fn this(&self) -> Local<'s, Object> {
|
2019-12-30 22:48:23 +01:00
|
|
|
unsafe {
|
2020-01-04 15:23:36 +01:00
|
|
|
Local::from_raw(v8__PropertyCallbackInfo__This(self.info)).unwrap()
|
2019-12-30 22:48:23 +01:00
|
|
|
}
|
|
|
|
}
|
2019-12-11 04:43:22 +01:00
|
|
|
}
|
|
|
|
|
2020-01-04 15:23:36 +01:00
|
|
|
pub type FunctionCallback = extern "C" fn(*const FunctionCallbackInfo);
|
|
|
|
|
|
|
|
impl<F> MapFnFrom<F> for FunctionCallback
|
|
|
|
where
|
2020-06-03 07:38:34 +02:00
|
|
|
F: UnitType + Fn(&mut HandleScope, FunctionCallbackArguments, ReturnValue),
|
2020-01-04 15:23:36 +01:00
|
|
|
{
|
|
|
|
fn mapping() -> Self {
|
|
|
|
let f = |info: *const FunctionCallbackInfo| {
|
2020-06-03 07:38:34 +02:00
|
|
|
let scope = &mut unsafe { CallbackScope::new(&*info) };
|
2020-01-04 15:23:36 +01:00
|
|
|
let args = FunctionCallbackArguments::from_function_callback_info(info);
|
|
|
|
let rv = ReturnValue::from_function_callback_info(info);
|
|
|
|
(F::get())(scope, args, rv);
|
|
|
|
};
|
|
|
|
f.to_c_fn()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// AccessorNameGetterCallback is used as callback functions when getting a
|
|
|
|
/// particular property. See Object and ObjectTemplate's method SetAccessor.
|
2020-01-17 07:39:05 +01:00
|
|
|
pub type AccessorNameGetterCallback<'s> =
|
|
|
|
extern "C" fn(Local<'s, Name>, *const PropertyCallbackInfo);
|
2020-01-04 15:23:36 +01:00
|
|
|
|
2020-01-17 07:39:05 +01:00
|
|
|
impl<F> MapFnFrom<F> for AccessorNameGetterCallback<'_>
|
2020-01-04 15:23:36 +01:00
|
|
|
where
|
|
|
|
F: UnitType
|
2020-06-03 07:38:34 +02:00
|
|
|
+ Fn(&mut HandleScope, Local<Name>, PropertyCallbackArguments, ReturnValue),
|
2020-01-04 15:23:36 +01:00
|
|
|
{
|
|
|
|
fn mapping() -> Self {
|
2020-01-17 07:39:05 +01:00
|
|
|
let f = |key: Local<Name>, info: *const PropertyCallbackInfo| {
|
2020-06-03 07:38:34 +02:00
|
|
|
let scope = &mut unsafe { CallbackScope::new(&*info) };
|
2020-01-04 15:23:36 +01:00
|
|
|
let args = PropertyCallbackArguments::from_property_callback_info(info);
|
|
|
|
let rv = ReturnValue::from_property_callback_info(info);
|
|
|
|
(F::get())(scope, key, args, rv);
|
|
|
|
};
|
|
|
|
f.to_c_fn()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-17 16:17:29 +01:00
|
|
|
pub type AccessorNameSetterCallback<'s> =
|
|
|
|
extern "C" fn(Local<'s, Name>, Local<'s, Value>, *const PropertyCallbackInfo);
|
|
|
|
|
|
|
|
impl<F> MapFnFrom<F> for AccessorNameSetterCallback<'_>
|
|
|
|
where
|
|
|
|
F: UnitType
|
|
|
|
+ Fn(&mut HandleScope, Local<Name>, Local<Value>, PropertyCallbackArguments),
|
|
|
|
{
|
|
|
|
fn mapping() -> Self {
|
|
|
|
let f = |key: Local<Name>,
|
|
|
|
value: Local<Value>,
|
|
|
|
info: *const PropertyCallbackInfo| {
|
|
|
|
let scope = &mut unsafe { CallbackScope::new(&*info) };
|
|
|
|
let args = PropertyCallbackArguments::from_property_callback_info(info);
|
|
|
|
(F::get())(scope, key, value, args);
|
|
|
|
};
|
|
|
|
f.to_c_fn()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-11 04:43:22 +01:00
|
|
|
impl Function {
|
|
|
|
// TODO: add remaining arguments from C++
|
|
|
|
/// Create a function in the current execution context
|
|
|
|
/// for a given FunctionCallback.
|
2020-06-03 07:38:34 +02:00
|
|
|
pub fn new<'s>(
|
|
|
|
scope: &mut HandleScope<'s>,
|
2020-01-04 15:23:36 +01:00
|
|
|
callback: impl MapFnTo<FunctionCallback>,
|
2020-06-03 07:38:34 +02:00
|
|
|
) -> Option<Local<'s, Function>> {
|
2020-01-04 15:23:36 +01:00
|
|
|
unsafe {
|
2020-06-26 02:56:24 +02:00
|
|
|
scope.cast_local(|sd| {
|
|
|
|
v8__Function__New(sd.get_current_context(), callback.map_fn_to())
|
|
|
|
})
|
2020-01-04 15:23:36 +01:00
|
|
|
}
|
2019-12-11 04:43:22 +01:00
|
|
|
}
|
|
|
|
|
2020-03-14 19:42:18 -07:00
|
|
|
/// Create a function in the current execution context
|
|
|
|
/// for a given FunctionCallback and associated data.
|
2020-06-03 07:38:34 +02:00
|
|
|
pub fn new_with_data<'s>(
|
|
|
|
scope: &mut HandleScope<'s>,
|
2020-03-14 19:42:18 -07:00
|
|
|
data: Local<Value>,
|
|
|
|
callback: impl MapFnTo<FunctionCallback>,
|
2020-06-03 07:38:34 +02:00
|
|
|
) -> Option<Local<'s, Function>> {
|
2020-03-14 19:42:18 -07:00
|
|
|
unsafe {
|
2020-06-26 02:56:24 +02:00
|
|
|
scope.cast_local(|sd| {
|
|
|
|
v8__Function__NewWithData(
|
|
|
|
sd.get_current_context(),
|
|
|
|
callback.map_fn_to(),
|
|
|
|
&*data,
|
|
|
|
)
|
2020-05-31 15:00:23 +02:00
|
|
|
})
|
2020-03-14 19:42:18 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-03 07:38:34 +02:00
|
|
|
pub fn call<'s>(
|
2020-01-17 03:56:34 +01:00
|
|
|
&self,
|
2020-06-03 07:38:34 +02:00
|
|
|
scope: &mut HandleScope<'s>,
|
2020-01-17 03:56:34 +01:00
|
|
|
recv: Local<Value>,
|
|
|
|
args: &[Local<Value>],
|
2020-06-03 07:38:34 +02:00
|
|
|
) -> Option<Local<'s, Value>> {
|
2020-04-13 14:43:56 +02:00
|
|
|
let args = Local::slice_into_raw(args);
|
2020-01-17 03:56:34 +01:00
|
|
|
let argc = int::try_from(args.len()).unwrap();
|
2020-04-13 14:43:56 +02:00
|
|
|
let argv = args.as_ptr();
|
2019-12-11 04:43:22 +01:00
|
|
|
unsafe {
|
2020-06-26 02:56:24 +02:00
|
|
|
scope.cast_local(|sd| {
|
|
|
|
v8__Function__Call(self, sd.get_current_context(), &*recv, argc, argv)
|
|
|
|
})
|
2019-12-11 04:43:22 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|