mirror of
https://github.com/denoland/rusty_v8.git
synced 2024-12-24 08:09:16 -05:00
Add Isolate::set_promise_hook() (#496)
This commit is contained in:
parent
ea0c7c9383
commit
57390ec4ee
4 changed files with 90 additions and 0 deletions
|
@ -188,6 +188,10 @@ void v8__Isolate__RequestInterrupt(v8::Isolate* isolate,
|
|||
isolate->RequestInterrupt(callback, data);
|
||||
}
|
||||
|
||||
void v8__Isolate__SetPromiseHook(v8::Isolate* isolate, v8::PromiseHook hook) {
|
||||
isolate->SetPromiseHook(hook);
|
||||
}
|
||||
|
||||
void v8__Isolate__SetPromiseRejectCallback(v8::Isolate* isolate,
|
||||
v8::PromiseRejectCallback callback) {
|
||||
isolate->SetPromiseRejectCallback(callback);
|
||||
|
|
|
@ -42,8 +42,34 @@ pub enum MicrotasksPolicy {
|
|||
Auto = 2,
|
||||
}
|
||||
|
||||
/// PromiseHook with type Init is called when a new promise is
|
||||
/// created. When a new promise is created as part of the chain in the
|
||||
/// case of Promise.then or in the intermediate promises created by
|
||||
/// Promise.{race, all}/AsyncFunctionAwait, we pass the parent promise
|
||||
/// otherwise we pass undefined.
|
||||
///
|
||||
/// PromiseHook with type Resolve is called at the beginning of
|
||||
/// resolve or reject function defined by CreateResolvingFunctions.
|
||||
///
|
||||
/// PromiseHook with type Before is called at the beginning of the
|
||||
/// PromiseReactionJob.
|
||||
///
|
||||
/// PromiseHook with type After is called right at the end of the
|
||||
/// PromiseReactionJob.
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub enum PromiseHookType {
|
||||
Init,
|
||||
Resolve,
|
||||
Before,
|
||||
After,
|
||||
}
|
||||
|
||||
pub type MessageCallback = extern "C" fn(Local<Message>, Local<Value>);
|
||||
|
||||
pub type PromiseHook =
|
||||
extern "C" fn(PromiseHookType, Local<Promise>, Local<Value>);
|
||||
|
||||
pub type PromiseRejectCallback = extern "C" fn(PromiseRejectMessage);
|
||||
|
||||
/// HostInitializeImportMetaObjectCallback is called the first time import.meta
|
||||
|
@ -127,6 +153,7 @@ extern "C" {
|
|||
callback: NearHeapLimitCallback,
|
||||
heap_limit: usize,
|
||||
);
|
||||
fn v8__Isolate__SetPromiseHook(isolate: *mut Isolate, hook: PromiseHook);
|
||||
fn v8__Isolate__SetPromiseRejectCallback(
|
||||
isolate: *mut Isolate,
|
||||
callback: PromiseRejectCallback,
|
||||
|
@ -398,6 +425,12 @@ impl Isolate {
|
|||
unsafe { v8__Isolate__AddMessageListener(self, callback) }
|
||||
}
|
||||
|
||||
/// Set the PromiseHook callback for various promise lifecycle
|
||||
/// events.
|
||||
pub fn set_promise_hook(&mut self, hook: PromiseHook) {
|
||||
unsafe { v8__Isolate__SetPromiseHook(self, hook) }
|
||||
}
|
||||
|
||||
/// Set callback to notify about promise reject with no handler, or
|
||||
/// revocation of such a previous notification once the handler is added.
|
||||
pub fn set_promise_reject_callback(
|
||||
|
|
|
@ -98,6 +98,8 @@ pub use isolate::MessageCallback;
|
|||
pub use isolate::MicrotasksPolicy;
|
||||
pub use isolate::NearHeapLimitCallback;
|
||||
pub use isolate::OwnedIsolate;
|
||||
pub use isolate::PromiseHook;
|
||||
pub use isolate::PromiseHookType;
|
||||
pub use isolate::PromiseRejectCallback;
|
||||
pub use isolate_create_params::CreateParams;
|
||||
pub use module::*;
|
||||
|
|
|
@ -1726,6 +1726,57 @@ fn promise_reject_callback_no_value() {
|
|||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn promise_hook() {
|
||||
extern "C" fn hook(
|
||||
type_: v8::PromiseHookType,
|
||||
promise: v8::Local<v8::Promise>,
|
||||
_parent: v8::Local<v8::Value>,
|
||||
) {
|
||||
let scope = &mut unsafe { v8::CallbackScope::new(promise) };
|
||||
let context = promise.creation_context(scope);
|
||||
let scope = &mut v8::ContextScope::new(scope, context);
|
||||
let global = context.global(scope);
|
||||
let name = v8::String::new(scope, "hook").unwrap();
|
||||
let func = global.get(scope, name.into()).unwrap();
|
||||
let func = v8::Local::<v8::Function>::try_from(func).unwrap();
|
||||
let args = &[v8::Integer::new(scope, type_ as i32).into(), promise.into()];
|
||||
func.call(scope, global.into(), args).unwrap();
|
||||
}
|
||||
let _setup_guard = setup();
|
||||
let isolate = &mut v8::Isolate::new(Default::default());
|
||||
isolate.set_promise_hook(hook);
|
||||
{
|
||||
let scope = &mut v8::HandleScope::new(isolate);
|
||||
let context = v8::Context::new(scope);
|
||||
let scope = &mut v8::ContextScope::new(scope, context);
|
||||
let source = r#"
|
||||
var promises = new Set();
|
||||
function hook(type, promise) {
|
||||
if (type === /* Init */ 0) promises.add(promise);
|
||||
if (type === /* Resolve */ 1) promises.delete(promise);
|
||||
}
|
||||
function expect(expected, actual = promises.size) {
|
||||
if (actual !== expected) throw `expected ${expected}, actual ${actual}`;
|
||||
}
|
||||
expect(0);
|
||||
new Promise(resolve => {
|
||||
expect(1);
|
||||
resolve();
|
||||
expect(0);
|
||||
});
|
||||
expect(0);
|
||||
new Promise(() => {});
|
||||
expect(1);
|
||||
promises.values().next().value
|
||||
"#;
|
||||
let promise = eval(scope, source).unwrap();
|
||||
let promise = v8::Local::<v8::Promise>::try_from(promise).unwrap();
|
||||
assert!(!promise.has_handler());
|
||||
assert_eq!(promise.state(), v8::PromiseState::Pending);
|
||||
}
|
||||
}
|
||||
|
||||
fn mock_script_origin<'s>(
|
||||
scope: &mut v8::HandleScope<'s>,
|
||||
resource_name_: &str,
|
||||
|
|
Loading…
Reference in a new issue