mirror of
https://github.com/lexmount/moli.git
synced 2026-10-02 00:00:49 +00:00
80 lines
2.6 KiB
Rust
80 lines
2.6 KiB
Rust
use moli_v8_util::v8str;
|
|
|
|
type MemberCallback = for<'s, 'i> fn(
|
|
&mut v8::PinScope<'s, 'i>,
|
|
v8::FunctionCallbackArguments<'s>,
|
|
v8::ReturnValue<'s>,
|
|
);
|
|
|
|
/// Completes native constructor identity only after a successful callback.
|
|
/// Callback data, subclass receivers, and replacement return objects retain
|
|
/// their original V8 semantics.
|
|
#[doc(hidden)]
|
|
pub fn invoke_web_api_constructor<'s>(
|
|
scope: &mut v8::PinScope<'s, '_>,
|
|
args: v8::FunctionCallbackArguments<'s>,
|
|
rv: v8::ReturnValue<'s>,
|
|
interface: crate::WebApiInterfaceDescriptor,
|
|
callback: MemberCallback,
|
|
) {
|
|
let receiver = args.this();
|
|
let construct = args.is_construct_call();
|
|
v8::tc_scope!(let scope, scope);
|
|
callback(scope, args, rv);
|
|
if scope.has_caught() {
|
|
scope.rethrow();
|
|
return;
|
|
}
|
|
if !scope.can_continue() {
|
|
return;
|
|
}
|
|
let result = rv.get(scope);
|
|
let object = match v8::Local::<v8::Object>::try_from(result) {
|
|
Ok(object) => object,
|
|
Err(_) if construct => receiver,
|
|
Err(_) => return,
|
|
};
|
|
if let Err(error) = interface.initialize(scope, object) {
|
|
let message =
|
|
v8::String::new(scope, &error.to_string()).expect("constructor identity error");
|
|
let exception = v8::Exception::type_error(scope, message);
|
|
scope.throw_exception(exception);
|
|
scope.rethrow();
|
|
}
|
|
}
|
|
|
|
pub fn throw_illegal_invocation(scope: &mut v8::PinScope<'_, '_>) {
|
|
let message = v8str(scope, "Illegal invocation");
|
|
let exception = v8::Exception::type_error(scope, message);
|
|
scope.throw_exception(exception);
|
|
}
|
|
|
|
/// Like Blink's ExceptionToRejectPromiseScope, this covers both receiver checks
|
|
/// and exceptions thrown by the implementation (including argument conversion).
|
|
/// It does not wrap successful results, preserving cached Promise identity.
|
|
pub fn invoke_promise_callback<'s>(
|
|
scope: &mut v8::PinScope<'s, '_>,
|
|
args: v8::FunctionCallbackArguments<'s>,
|
|
mut rv: v8::ReturnValue<'s>,
|
|
callback: MemberCallback,
|
|
) {
|
|
v8::tc_scope!(let scope, scope);
|
|
callback(scope, args, rv);
|
|
// Termination is not a catchable WebIDL exception. Leave it to V8.
|
|
if !scope.can_continue() {
|
|
return;
|
|
}
|
|
let Some(exception) = scope.exception() else {
|
|
return;
|
|
};
|
|
scope.reset();
|
|
// The callback's current realm supplies both TypeError and Promise, even
|
|
// when its receiver or caller belongs to a different realm.
|
|
let Some(resolver) = v8::PromiseResolver::new(scope) else {
|
|
return;
|
|
};
|
|
if resolver.reject(scope, exception).is_some() {
|
|
rv.set(resolver.get_promise(scope).into());
|
|
}
|
|
}
|