use std::alloc::alloc;
use std::alloc::Layout;
use std::any::type_name;
use std::cell::Cell;
use std::convert::TryInto;
use std::marker::PhantomData;
use std::mem::MaybeUninit;
use std::num::NonZeroUsize;
use std::ops::Deref;
use std::ops::DerefMut;
use std::ptr;
use std::ptr::NonNull;
use crate::function::FunctionCallbackInfo;
use crate::function::PropertyCallbackInfo;
use crate::Context;
use crate::Data;
use crate::DataError;
use crate::Handle;
use crate::Isolate;
use crate::Local;
use crate::Message;
use crate::Object;
use crate::OwnedIsolate;
use crate::Primitive;
use crate::PromiseRejectMessage;
use crate::Value;
#[derive(Debug)]
pub struct ContextScope<'s, P> {
data: NonNull<data::ScopeData>,
_phantom: PhantomData<&'s mut P>,
}
impl<'s, P: param::NewContextScope<'s>> ContextScope<'s, P> {
#[allow(clippy::new_ret_no_self)]
pub fn new(param: &'s mut P, context: Local<Context>) -> P::NewScope {
let scope_data = param.get_scope_data_mut();
if scope_data.get_isolate_ptr()
!= unsafe { raw::v8__Context__GetIsolate(&*context) }
{
panic!(
"{} and Context do not belong to the same Isolate",
type_name::<P>()
)
}
let new_scope_data = scope_data.new_context_scope_data(context);
new_scope_data.as_scope()
}
}
#[derive(Debug)]
pub struct HandleScope<'s, C = Context> {
data: NonNull<data::ScopeData>,
_phantom: PhantomData<&'s mut C>,
}
impl<'s> HandleScope<'s> {
#[allow(clippy::new_ret_no_self)]
pub fn new<P: param::NewHandleScope<'s>>(param: &'s mut P) -> P::NewScope {
param
.get_scope_data_mut()
.new_handle_scope_data()
.as_scope()
}
pub fn with_context<
P: param::NewHandleScopeWithContext<'s>,
H: Handle<Data = Context>,
>(
param: &'s mut P,
context: H,
) -> Self {
let context_ref = context.get(param.get_isolate_mut());
param
.get_scope_data_mut()
.new_handle_scope_data_with_context(context_ref)
.as_scope()
}
pub fn get_current_context(&self) -> Local<'s, Context> {
let context_ptr = data::ScopeData::get(self).get_current_context();
unsafe { Local::from_raw(context_ptr) }.unwrap()
}
pub fn get_entered_or_microtask_context(&self) -> Local<'s, Context> {
let data = data::ScopeData::get(self);
let isolate_ptr = data.get_isolate_ptr();
let context_ptr =
unsafe { raw::v8__Isolate__GetEnteredOrMicrotaskContext(isolate_ptr) };
unsafe { Local::from_raw(context_ptr) }.unwrap()
}
}
impl<'s> HandleScope<'s, ()> {
pub fn throw_exception(
&mut self,
exception: Local<Value>,
) -> Local<'s, Value> {
unsafe {
self.cast_local(|sd| {
raw::v8__Isolate__ThrowException(sd.get_isolate_ptr(), &*exception)
})
}
.unwrap()
}
pub(crate) unsafe fn cast_local<T>(
&mut self,
f: impl FnOnce(&mut data::ScopeData) -> *const T,
) -> Option<Local<'s, T>> {
Local::from_raw(f(data::ScopeData::get_mut(self)))
}
pub(crate) fn get_isolate_ptr(&self) -> *mut Isolate {
data::ScopeData::get(self).get_isolate_ptr()
}
}
impl<'s> HandleScope<'s> {
pub fn get_isolate_data_from_snapshot_once<T>(
&mut self,
index: usize,
) -> Result<Local<'s, T>, DataError>
where
T: 'static,
for<'l> Local<'l, Data>: TryInto<Local<'l, T>, Error = DataError>,
{
unsafe {
self
.cast_local(|sd| {
raw::v8__Isolate__GetDataFromSnapshotOnce(sd.get_isolate_ptr(), index)
})
.ok_or_else(DataError::no_data::<T>)
.and_then(|data| data.try_into())
}
}
pub fn get_context_data_from_snapshot_once<T>(
&mut self,
index: usize,
) -> Result<Local<'s, T>, DataError>
where
T: 'static,
for<'l> Local<'l, Data>: TryInto<Local<'l, T>, Error = DataError>,
{
unsafe {
self
.cast_local(|sd| {
raw::v8__Context__GetDataFromSnapshotOnce(
sd.get_current_context(),
index,
)
})
.ok_or_else(DataError::no_data::<T>)
.and_then(|data| data.try_into())
}
}
}
#[derive(Debug)]
pub struct EscapableHandleScope<'s, 'e: 's, C = Context> {
data: NonNull<data::ScopeData>,
_phantom:
PhantomData<(&'s mut raw::HandleScope, &'e mut raw::EscapeSlot, &'s C)>,
}
impl<'s, 'e: 's> EscapableHandleScope<'s, 'e> {
#[allow(clippy::new_ret_no_self)]
pub fn new<P: param::NewEscapableHandleScope<'s, 'e>>(
param: &'s mut P,
) -> P::NewScope {
param
.get_scope_data_mut()
.new_escapable_handle_scope_data()
.as_scope()
}
}
impl<'s, 'e: 's, C> EscapableHandleScope<'s, 'e, C> {
pub fn escape<T>(&mut self, value: Local<T>) -> Local<'e, T>
where
for<'l> Local<'l, T>: Into<Local<'l, Data>>,
{
let escape_slot = data::ScopeData::get_mut(self)
.get_escape_slot_mut()
.expect("internal error: EscapableHandleScope has no escape slot")
.take()
.expect("EscapableHandleScope::escape() called twice");
escape_slot.escape(value)
}
}
#[derive(Debug)]
pub struct TryCatch<'s, P> {
data: NonNull<data::ScopeData>,
_phantom: PhantomData<&'s mut P>,
}
impl<'s, P: param::NewTryCatch<'s>> TryCatch<'s, P> {
#[allow(clippy::new_ret_no_self)]
pub fn new(param: &'s mut P) -> P::NewScope {
param.get_scope_data_mut().new_try_catch_data().as_scope()
}
}
impl<'s, P> TryCatch<'s, P> {
pub fn has_caught(&self) -> bool {
unsafe { raw::v8__TryCatch__HasCaught(self.get_raw()) }
}
pub fn can_continue(&self) -> bool {
unsafe { raw::v8__TryCatch__CanContinue(self.get_raw()) }
}
pub fn has_terminated(&self) -> bool {
unsafe { raw::v8__TryCatch__HasTerminated(self.get_raw()) }
}
pub fn is_verbose(&self) -> bool {
unsafe { raw::v8__TryCatch__IsVerbose(self.get_raw()) }
}
pub fn set_verbose(&mut self, value: bool) {
unsafe { raw::v8__TryCatch__SetVerbose(self.get_raw_mut(), value) };
}
pub fn set_capture_message(&mut self, value: bool) {
unsafe { raw::v8__TryCatch__SetCaptureMessage(self.get_raw_mut(), value) };
}
pub fn reset(&mut self) {
unsafe { raw::v8__TryCatch__Reset(self.get_raw_mut()) };
}
fn get_raw(&self) -> &raw::TryCatch {
data::ScopeData::get(self).get_try_catch()
}
fn get_raw_mut(&mut self) -> &mut raw::TryCatch {
data::ScopeData::get_mut(self).get_try_catch_mut()
}
}
impl<'s, 'p: 's, P> TryCatch<'s, P>
where
Self: AsMut<HandleScope<'p, ()>>,
{
pub fn exception(&mut self) -> Option<Local<'p, Value>> {
unsafe {
self
.as_mut()
.cast_local(|sd| raw::v8__TryCatch__Exception(sd.get_try_catch()))
}
}
pub fn message(&mut self) -> Option<Local<'p, Message>> {
unsafe {
self
.as_mut()
.cast_local(|sd| raw::v8__TryCatch__Message(sd.get_try_catch()))
}
}
pub fn rethrow(&mut self) -> Option<Local<'_, Value>> {
unsafe {
self
.as_mut()
.cast_local(|sd| raw::v8__TryCatch__ReThrow(sd.get_try_catch_mut()))
}
}
}
impl<'s, 'p: 's, P> TryCatch<'s, P>
where
Self: AsMut<HandleScope<'p>>,
{
pub fn stack_trace(&mut self) -> Option<Local<'p, Value>> {
unsafe {
self.as_mut().cast_local(|sd| {
raw::v8__TryCatch__StackTrace(
sd.get_try_catch(),
sd.get_current_context(),
)
})
}
}
}
#[derive(Debug)]
pub struct CallbackScope<'s, C = Context> {
data: NonNull<data::ScopeData>,
_phantom: PhantomData<&'s mut HandleScope<'s, C>>,
}
impl<'s> CallbackScope<'s> {
#[allow(clippy::new_ret_no_self)]
pub unsafe fn new<P: param::NewCallbackScope<'s>>(param: P) -> P::NewScope {
let (isolate, context) = param.get_isolate_mut_and_maybe_current_context();
data::ScopeData::get_current_mut(isolate)
.new_callback_scope_data(context)
.as_scope()
}
}
macro_rules! impl_as {
(<$($params:tt),+> $src_type:ty as Isolate) => {
impl<$($params),*> AsRef<Isolate> for $src_type {
fn as_ref(&self) -> &Isolate {
data::ScopeData::get(self).get_isolate()
}
}
impl<$($params),*> AsMut<Isolate> for $src_type {
fn as_mut(&mut self) -> &mut Isolate {
data::ScopeData::get_mut(self).get_isolate_mut()
}
}
};
(<$($params:tt),+> $src_type:ty as $tgt_type:ty) => {
impl<$($params),*> AsRef<$tgt_type> for $src_type {
fn as_ref(&self) -> &$tgt_type {
self.cast_ref()
}
}
impl<$($params),*> AsMut< $tgt_type> for $src_type {
fn as_mut(&mut self) -> &mut $tgt_type {
self.cast_mut()
}
}
};
}
impl_as!(<'s, 'p, P> ContextScope<'s, P> as Isolate);
impl_as!(<'s, C> HandleScope<'s, C> as Isolate);
impl_as!(<'s, 'e, C> EscapableHandleScope<'s, 'e, C> as Isolate);
impl_as!(<'s, P> TryCatch<'s, P> as Isolate);
impl_as!(<'s, C> CallbackScope<'s, C> as Isolate);
impl_as!(<'s, 'p> ContextScope<'s, HandleScope<'p>> as HandleScope<'p, ()>);
impl_as!(<'s, 'p, 'e> ContextScope<'s, EscapableHandleScope<'p, 'e>> as HandleScope<'p, ()>);
impl_as!(<'s, C> HandleScope<'s, C> as HandleScope<'s, ()>);
impl_as!(<'s, 'e, C> EscapableHandleScope<'s, 'e, C> as HandleScope<'s, ()>);
impl_as!(<'s, 'p, C> TryCatch<'s, HandleScope<'p, C>> as HandleScope<'p, ()>);
impl_as!(<'s, 'p, 'e, C> TryCatch<'s, EscapableHandleScope<'p, 'e, C>> as HandleScope<'p, ()>);
impl_as!(<'s, C> CallbackScope<'s, C> as HandleScope<'s, ()>);
impl_as!(<'s, 'p> ContextScope<'s, HandleScope<'p>> as HandleScope<'p>);
impl_as!(<'s, 'p, 'e> ContextScope<'s, EscapableHandleScope<'p, 'e>> as HandleScope<'p>);
impl_as!(<'s> HandleScope<'s> as HandleScope<'s>);
impl_as!(<'s, 'e> EscapableHandleScope<'s, 'e> as HandleScope<'s>);
impl_as!(<'s, 'p> TryCatch<'s, HandleScope<'p>> as HandleScope<'p>);
impl_as!(<'s, 'p, 'e> TryCatch<'s, EscapableHandleScope<'p, 'e>> as HandleScope<'p>);
impl_as!(<'s> CallbackScope<'s> as HandleScope<'s>);
impl_as!(<'s, 'p, 'e> ContextScope<'s, EscapableHandleScope<'p, 'e>> as EscapableHandleScope<'p, 'e, ()>);
impl_as!(<'s, 'e, C> EscapableHandleScope<'s, 'e, C> as EscapableHandleScope<'s, 'e, ()>);
impl_as!(<'s, 'p, 'e, C> TryCatch<'s, EscapableHandleScope<'p, 'e, C>> as EscapableHandleScope<'p, 'e, ()>);
impl_as!(<'s, 'p, 'e> ContextScope<'s, EscapableHandleScope<'p, 'e>> as EscapableHandleScope<'p, 'e>);
impl_as!(<'s, 'e> EscapableHandleScope<'s, 'e> as EscapableHandleScope<'s, 'e>);
impl_as!(<'s, 'p, 'e> TryCatch<'s, EscapableHandleScope<'p, 'e>> as EscapableHandleScope<'p, 'e>);
impl_as!(<'s, 'p, C> TryCatch<'s, HandleScope<'p, C>> as TryCatch<'s, HandleScope<'p, ()>>);
impl_as!(<'s, 'p, 'e, C> TryCatch<'s, EscapableHandleScope<'p, 'e, C>> as TryCatch<'s, HandleScope<'p, ()>>);
impl_as!(<'s, 'p, 'e, C> TryCatch<'s, EscapableHandleScope<'p, 'e, C>> as TryCatch<'s, EscapableHandleScope<'p, 'e, ()>>);
impl_as!(<'s, 'p> TryCatch<'s, HandleScope<'p>> as TryCatch<'s, HandleScope<'p>>);
impl_as!(<'s, 'p, 'e> TryCatch<'s, EscapableHandleScope<'p, 'e>> as TryCatch<'s, HandleScope<'p>>);
impl_as!(<'s, 'p, 'e> TryCatch<'s, EscapableHandleScope<'p, 'e>> as TryCatch<'s, EscapableHandleScope<'p, 'e>>);
macro_rules! impl_deref {
(<$($params:tt),+> $src_type:ty as $tgt_type:ty) => {
impl<$($params),*> Deref for $src_type {
type Target = $tgt_type;
fn deref(&self) -> &Self::Target {
self.as_ref()
}
}
impl<$($params),*> DerefMut for $src_type {
fn deref_mut(&mut self) -> &mut Self::Target {
self.as_mut()
}
}
};
}
impl_deref!(<'s, 'p> ContextScope<'s, HandleScope<'p>> as HandleScope<'p>);
impl_deref!(<'s, 'p, 'e> ContextScope<'s, EscapableHandleScope<'p, 'e>> as EscapableHandleScope<'p, 'e>);
impl_deref!(<'s> HandleScope<'s, ()> as Isolate);
impl_deref!(<'s> HandleScope<'s> as HandleScope<'s, ()>);
impl_deref!(<'s, 'e> EscapableHandleScope<'s, 'e, ()> as HandleScope<'s, ()>);
impl_deref!(<'s, 'e> EscapableHandleScope<'s, 'e> as HandleScope<'s>);
impl_deref!(<'s, 'p> TryCatch<'s, HandleScope<'p, ()>> as HandleScope<'p, ()>);
impl_deref!(<'s, 'p> TryCatch<'s, HandleScope<'p>> as HandleScope<'p>);
impl_deref!(<'s, 'p, 'e> TryCatch<'s, EscapableHandleScope<'p, 'e, ()>> as EscapableHandleScope<'p, 'e, ()>);
impl_deref!(<'s, 'p, 'e> TryCatch<'s, EscapableHandleScope<'p, 'e>> as EscapableHandleScope<'p, 'e>);
impl_deref!(<'s> CallbackScope<'s, ()> as HandleScope<'s, ()>);
impl_deref!(<'s> CallbackScope<'s> as HandleScope<'s>);
macro_rules! impl_scope_drop {
(<$($params:tt),+> $type:ty) => {
unsafe impl<$($params),*> Scope for $type {}
impl<$($params),*> Drop for $type {
fn drop(&mut self) {
data::ScopeData::get_mut(self).notify_scope_dropped();
}
}
};
}
impl_scope_drop!(<'s, 'p, P> ContextScope<'s, P>);
impl_scope_drop!(<'s, C> HandleScope<'s, C> );
impl_scope_drop!(<'s, 'e, C> EscapableHandleScope<'s, 'e, C> );
impl_scope_drop!(<'s, P> TryCatch<'s, P> );
impl_scope_drop!(<'s, C> CallbackScope<'s, C> );
pub unsafe trait Scope: Sized {}
trait ScopeCast: Sized {
fn cast_ref<S: Scope>(&self) -> &S;
fn cast_mut<S: Scope>(&mut self) -> &mut S;
}
impl<T: Scope> ScopeCast for T {
fn cast_ref<S: Scope>(&self) -> &S {
assert_eq!(Layout::new::<Self>(), Layout::new::<S>());
unsafe { &*(self as *const _ as *const S) }
}
fn cast_mut<S: Scope>(&mut self) -> &mut S {
assert_eq!(Layout::new::<Self>(), Layout::new::<S>());
unsafe { &mut *(self as *mut _ as *mut S) }
}
}
mod param {
use super::*;
pub trait NewContextScope<'s>: getter::GetScopeData {
type NewScope: Scope;
}
impl<'s, 'p: 's, P: Scope> NewContextScope<'s> for ContextScope<'p, P> {
type NewScope = ContextScope<'s, P>;
}
impl<'s, 'p: 's, C> NewContextScope<'s> for HandleScope<'p, C> {
type NewScope = ContextScope<'s, HandleScope<'p>>;
}
impl<'s, 'p: 's, 'e: 'p, C> NewContextScope<'s>
for EscapableHandleScope<'p, 'e, C>
{
type NewScope = ContextScope<'s, EscapableHandleScope<'p, 'e>>;
}
impl<'s, 'p: 's, P: NewContextScope<'s>> NewContextScope<'s>
for TryCatch<'p, P>
{
type NewScope = <P as NewContextScope<'s>>::NewScope;
}
impl<'s, 'p: 's, C> NewContextScope<'s> for CallbackScope<'p, C> {
type NewScope = ContextScope<'s, HandleScope<'p>>;
}
pub trait NewHandleScope<'s>: getter::GetScopeData {
type NewScope: Scope;
}
impl<'s> NewHandleScope<'s> for Isolate {
type NewScope = HandleScope<'s, ()>;
}
impl<'s> NewHandleScope<'s> for OwnedIsolate {
type NewScope = HandleScope<'s, ()>;
}
impl<'s, 'p: 's, P: NewHandleScope<'s>> NewHandleScope<'s>
for ContextScope<'p, P>
{
type NewScope = <P as NewHandleScope<'s>>::NewScope;
}
impl<'s, 'p: 's, C> NewHandleScope<'s> for HandleScope<'p, C> {
type NewScope = HandleScope<'s, C>;
}
impl<'s, 'p: 's, 'e: 'p, C> NewHandleScope<'s>
for EscapableHandleScope<'p, 'e, C>
{
type NewScope = EscapableHandleScope<'s, 'e, C>;
}
impl<'s, 'p: 's, P: NewHandleScope<'s>> NewHandleScope<'s> for TryCatch<'p, P> {
type NewScope = <P as NewHandleScope<'s>>::NewScope;
}
impl<'s, 'p: 's, C> NewHandleScope<'s> for CallbackScope<'p, C> {
type NewScope = HandleScope<'s, C>;
}
pub trait NewHandleScopeWithContext<'s>: getter::GetScopeData {
fn get_isolate_mut(&mut self) -> &mut Isolate;
}
impl<'s> NewHandleScopeWithContext<'s> for Isolate {
fn get_isolate_mut(&mut self) -> &mut Isolate {
self
}
}
impl<'s> NewHandleScopeWithContext<'s> for OwnedIsolate {
fn get_isolate_mut(&mut self) -> &mut Isolate {
&mut *self
}
}
pub trait NewEscapableHandleScope<'s, 'e: 's>: getter::GetScopeData {
type NewScope: Scope;
}
impl<'s, 'p: 's, 'e: 'p, P: NewEscapableHandleScope<'s, 'e>>
NewEscapableHandleScope<'s, 'e> for ContextScope<'p, P>
{
type NewScope = <P as NewEscapableHandleScope<'s, 'e>>::NewScope;
}
impl<'s, 'p: 's, C> NewEscapableHandleScope<'s, 'p> for HandleScope<'p, C> {
type NewScope = EscapableHandleScope<'s, 'p, C>;
}
impl<'s, 'p: 's, 'e: 'p, C> NewEscapableHandleScope<'s, 'p>
for EscapableHandleScope<'p, 'e, C>
{
type NewScope = EscapableHandleScope<'s, 'p, C>;
}
impl<'s, 'p: 's, 'e: 'p, P: NewEscapableHandleScope<'s, 'e>>
NewEscapableHandleScope<'s, 'e> for TryCatch<'p, P>
{
type NewScope = <P as NewEscapableHandleScope<'s, 'e>>::NewScope;
}
impl<'s, 'p: 's, C> NewEscapableHandleScope<'s, 'p> for CallbackScope<'p, C> {
type NewScope = EscapableHandleScope<'s, 'p, C>;
}
pub trait NewTryCatch<'s>: getter::GetScopeData {
type NewScope: Scope;
}
impl<'s, 'p: 's, P: NewTryCatch<'s>> NewTryCatch<'s> for ContextScope<'p, P> {
type NewScope = <P as NewTryCatch<'s>>::NewScope;
}
impl<'s, 'p: 's, C> NewTryCatch<'s> for HandleScope<'p, C> {
type NewScope = TryCatch<'s, HandleScope<'p, C>>;
}
impl<'s, 'p: 's, 'e: 'p, C> NewTryCatch<'s>
for EscapableHandleScope<'p, 'e, C>
{
type NewScope = TryCatch<'s, EscapableHandleScope<'p, 'e, C>>;
}
impl<'s, 'p: 's, P> NewTryCatch<'s> for TryCatch<'p, P> {
type NewScope = TryCatch<'s, P>;
}
impl<'s, 'p: 's, C> NewTryCatch<'s> for CallbackScope<'p, C> {
type NewScope = TryCatch<'s, HandleScope<'p, C>>;
}
pub trait NewCallbackScope<'s>: Sized + getter::GetIsolate<'s> {
type NewScope: Scope;
unsafe fn get_isolate_mut_and_maybe_current_context(
self,
) -> (&'s mut Isolate, Option<Local<'s, Context>>) {
(self.get_isolate_mut(), None)
}
}
impl<'s> NewCallbackScope<'s> for &'s mut Isolate {
type NewScope = CallbackScope<'s, ()>;
}
impl<'s> NewCallbackScope<'s> for &'s mut OwnedIsolate {
type NewScope = CallbackScope<'s, ()>;
}
impl<'s> NewCallbackScope<'s> for &'s FunctionCallbackInfo {
type NewScope = CallbackScope<'s>;
}
impl<'s> NewCallbackScope<'s> for &'s PropertyCallbackInfo {
type NewScope = CallbackScope<'s>;
}
impl<'s> NewCallbackScope<'s> for Local<'s, Context> {
type NewScope = CallbackScope<'s>;
unsafe fn get_isolate_mut_and_maybe_current_context(
self,
) -> (&'s mut Isolate, Option<Local<'s, Context>>) {
(getter::GetIsolate::get_isolate_mut(self), Some(self))
}
}
impl<'s> NewCallbackScope<'s> for Local<'s, Message> {
type NewScope = CallbackScope<'s>;
}
impl<'s, T: Into<Local<'s, Object>>> NewCallbackScope<'s> for T {
type NewScope = CallbackScope<'s>;
}
impl<'s> NewCallbackScope<'s> for &'s PromiseRejectMessage<'s> {
type NewScope = CallbackScope<'s>;
}
}
mod getter {
pub use super::*;
pub trait GetIsolate<'s> {
unsafe fn get_isolate_mut(self) -> &'s mut Isolate;
}
impl<'s> GetIsolate<'s> for &'s mut Isolate {
unsafe fn get_isolate_mut(self) -> &'s mut Isolate {
self
}
}
impl<'s> GetIsolate<'s> for &'s mut OwnedIsolate {
unsafe fn get_isolate_mut(self) -> &'s mut Isolate {
&mut *self
}
}
impl<'s> GetIsolate<'s> for &'s FunctionCallbackInfo {
unsafe fn get_isolate_mut(self) -> &'s mut Isolate {
&mut *raw::v8__FunctionCallbackInfo__GetIsolate(self)
}
}
impl<'s> GetIsolate<'s> for &'s PropertyCallbackInfo {
unsafe fn get_isolate_mut(self) -> &'s mut Isolate {
&mut *raw::v8__PropertyCallbackInfo__GetIsolate(self)
}
}
impl<'s> GetIsolate<'s> for Local<'s, Context> {
unsafe fn get_isolate_mut(self) -> &'s mut Isolate {
&mut *raw::v8__Context__GetIsolate(&*self)
}
}
impl<'s> GetIsolate<'s> for Local<'s, Message> {
unsafe fn get_isolate_mut(self) -> &'s mut Isolate {
&mut *raw::v8__Message__GetIsolate(&*self)
}
}
impl<'s, T: Into<Local<'s, Object>>> GetIsolate<'s> for T {
unsafe fn get_isolate_mut(self) -> &'s mut Isolate {
let object: Local<Object> = self.into();
&mut *raw::v8__Object__GetIsolate(&*object)
}
}
impl<'s> GetIsolate<'s> for &'s PromiseRejectMessage<'s> {
unsafe fn get_isolate_mut(self) -> &'s mut Isolate {
let object: Local<Object> = self.get_promise().into();
&mut *raw::v8__Object__GetIsolate(&*object)
}
}
pub trait GetScopeData {
fn get_scope_data_mut(&mut self) -> &mut data::ScopeData;
}
impl<T: Scope> GetScopeData for T {
fn get_scope_data_mut(&mut self) -> &mut data::ScopeData {
data::ScopeData::get_mut(self)
}
}
impl GetScopeData for Isolate {
fn get_scope_data_mut(&mut self) -> &mut data::ScopeData {
data::ScopeData::get_root_mut(self)
}
}
impl GetScopeData for OwnedIsolate {
fn get_scope_data_mut(&mut self) -> &mut data::ScopeData {
data::ScopeData::get_root_mut(self)
}
}
}
pub(crate) mod data {
use super::*;
#[derive(Debug)]
pub struct ScopeData {
isolate: NonNull<Isolate>,
previous: Option<NonNull<ScopeData>>,
next: Option<Box<ScopeData>>,
status: Cell<ScopeStatus>,
context: Cell<Option<NonNull<Context>>>,
escape_slot: Option<NonNull<Option<raw::EscapeSlot>>>,
try_catch: Option<NonNull<raw::TryCatch>>,
scope_type_specific_data: ScopeTypeSpecificData,
}
impl ScopeData {
pub(crate) fn get_current_mut(isolate: &mut Isolate) -> &mut Self {
let self_mut = isolate
.get_current_scope_data()
.map(NonNull::as_ptr)
.map(|p| unsafe { &mut *p })
.unwrap();
match self_mut.status.get() {
ScopeStatus::Current { .. } => self_mut,
_ => unreachable!(),
}
}
pub(crate) fn new_root(isolate: &mut Isolate) {
let root = Box::leak(Self::boxed(isolate.into()));
root.status = ScopeStatus::Current { zombie: false }.into();
debug_assert!(isolate.get_current_scope_data().is_none());
isolate.set_current_scope_data(Some(root.into()));
}
pub(crate) fn get_root_mut(isolate: &mut Isolate) -> &mut Self {
let mut current_scope_data = Self::get_current_mut(isolate);
loop {
current_scope_data = match current_scope_data {
root if root.previous.is_none() => break root,
data => data.try_exit_scope(),
};
}
}
pub(crate) fn drop_root(isolate: &mut Isolate) {
let root = Self::get_root_mut(isolate);
unsafe { Box::from_raw(root) };
isolate.set_current_scope_data(None);
}
pub(super) fn new_context_scope_data<'s>(
&'s mut self,
context: Local<'s, Context>,
) -> &'s mut Self {
self.new_scope_data_with(move |data| {
data.scope_type_specific_data.init_with(|| {
ScopeTypeSpecificData::ContextScope {
raw_context_scope: raw::ContextScope::new(context),
}
});
data.context.set(Some(context.as_non_null()));
})
}
#[inline(always)]
fn new_handle_scope_data_with<F>(&mut self, init_context_fn: F) -> &mut Self
where
F: FnOnce(
NonNull<Isolate>,
&mut Cell<Option<NonNull<Context>>>,
&mut Option<raw::ContextScope>,
),
{
self.new_scope_data_with(|data| {
let isolate = data.isolate;
data.scope_type_specific_data.init_with(|| {
ScopeTypeSpecificData::HandleScope {
raw_handle_scope: unsafe { raw::HandleScope::uninit() },
raw_context_scope: None,
}
});
match &mut data.scope_type_specific_data {
ScopeTypeSpecificData::HandleScope {
raw_handle_scope,
raw_context_scope,
} => {
unsafe { raw_handle_scope.init(isolate) };
init_context_fn(isolate, &mut data.context, raw_context_scope);
}
_ => unreachable!(),
};
})
}
pub(super) fn new_handle_scope_data(&mut self) -> &mut Self {
self.new_handle_scope_data_with(|_, _, raw_context_scope| {
debug_assert!(raw_context_scope.is_none())
})
}
pub(super) fn new_handle_scope_data_with_context(
&mut self,
context_ref: &Context,
) -> &mut Self {
self.new_handle_scope_data_with(
move |isolate, context_data, raw_context_scope| unsafe {
let context_nn = NonNull::from(context_ref);
let local_context_ptr =
raw::v8__Local__New(isolate.as_ptr(), context_nn.cast().as_ptr())
as *const Context;
let local_context_nn =
NonNull::new_unchecked(local_context_ptr as *mut _);
let local_context = Local::from_non_null(local_context_nn);
debug_assert!(raw_context_scope.is_none());
ptr::write(
raw_context_scope,
Some(raw::ContextScope::new(local_context)),
);
context_data.set(Some(local_context_nn));
},
)
}
pub(super) fn new_escapable_handle_scope_data(&mut self) -> &mut Self {
self.new_scope_data_with(|data| {
let isolate = data.isolate;
data.scope_type_specific_data.init_with(|| {
ScopeTypeSpecificData::EscapableHandleScope {
raw_handle_scope: unsafe { raw::HandleScope::uninit() },
raw_escape_slot: Some(raw::EscapeSlot::new(isolate)),
}
});
match &mut data.scope_type_specific_data {
ScopeTypeSpecificData::EscapableHandleScope {
raw_handle_scope,
raw_escape_slot,
} => {
unsafe { raw_handle_scope.init(isolate) };
data.escape_slot.replace(raw_escape_slot.into());
}
_ => unreachable!(),
}
})
}
pub(super) fn new_try_catch_data(&mut self) -> &mut Self {
self.new_scope_data_with(|data| {
let isolate = data.isolate;
data.scope_type_specific_data.init_with(|| {
ScopeTypeSpecificData::TryCatch {
raw_try_catch: unsafe { raw::TryCatch::uninit() },
}
});
match &mut data.scope_type_specific_data {
ScopeTypeSpecificData::TryCatch { raw_try_catch } => {
unsafe { raw_try_catch.init(isolate) };
data.try_catch.replace(raw_try_catch.into());
}
_ => unreachable!(),
}
})
}
pub(super) fn new_callback_scope_data<'s>(
&'s mut self,
maybe_current_context: Option<Local<'s, Context>>,
) -> &'s mut Self {
self.new_scope_data_with(|data| {
debug_assert!(data.scope_type_specific_data.is_none());
data
.context
.set(maybe_current_context.map(|cx| cx.as_non_null()));
})
}
fn new_scope_data_with(
&mut self,
init_fn: impl FnOnce(&mut Self),
) -> &mut Self {
self.status.set(match self.status.get() {
ScopeStatus::Current { zombie } => ScopeStatus::Shadowed { zombie },
_ => unreachable!(),
});
let context = self.context.get().into();
let escape_slot = self.escape_slot;
let new_scope_data = self.allocate_or_reuse_scope_data();
new_scope_data.status = Cell::new(ScopeStatus::Current {
zombie: cfg!(debug_assertions),
});
new_scope_data.context = context;
new_scope_data.escape_slot = escape_slot;
(init_fn)(new_scope_data);
let new_scope_nn = unsafe { NonNull::new_unchecked(new_scope_data) };
new_scope_data
.get_isolate_mut()
.set_current_scope_data(Some(new_scope_nn));
new_scope_data
}
fn allocate_or_reuse_scope_data(&mut self) -> &mut Self {
let self_nn = NonNull::new(self);
match &mut self.next {
Some(next_box) => {
debug_assert_eq!(next_box.isolate, self.isolate);
debug_assert_eq!(next_box.previous, self_nn);
debug_assert_eq!(next_box.status.get(), ScopeStatus::Free);
debug_assert!(next_box.scope_type_specific_data.is_none());
next_box.as_mut()
}
next_field @ None => {
let mut next_box = Self::boxed(self.isolate);
next_box.previous = self_nn;
next_field.replace(next_box);
next_field.as_mut().unwrap()
}
}
}
pub(super) fn as_scope<S: Scope>(&mut self) -> S {
assert_eq!(Layout::new::<&mut Self>(), Layout::new::<S>());
if cfg!(debug_assertions) {
assert_eq!(self.status.get(), ScopeStatus::Current { zombie: true });
self.status.set(ScopeStatus::Current { zombie: false });
}
let self_nn = NonNull::from(self);
unsafe { ptr::read(&self_nn as *const _ as *const S) }
}
pub(super) fn get<S: Scope>(scope: &S) -> &Self {
let self_mut = unsafe {
(*(scope as *const S as *mut S as *mut NonNull<Self>)).as_mut()
};
self_mut.try_activate_scope();
self_mut
}
pub(super) fn get_mut<S: Scope>(scope: &mut S) -> &mut Self {
let self_mut =
unsafe { (*(scope as *mut S as *mut NonNull<Self>)).as_mut() };
self_mut.try_activate_scope();
self_mut
}
#[inline(always)]
fn try_activate_scope(mut self: &mut Self) -> &mut Self {
self = match self.status.get() {
ScopeStatus::Current { zombie: false } => self,
ScopeStatus::Shadowed { zombie: false } => {
self.next.as_mut().unwrap().try_exit_scope()
}
_ => unreachable!(),
};
debug_assert_eq!(
self.get_isolate().get_current_scope_data(),
NonNull::new(self as *mut _)
);
self
}
fn try_exit_scope(mut self: &mut Self) -> &mut Self {
loop {
self = match self.status.get() {
ScopeStatus::Shadowed { .. } => {
self.next.as_mut().unwrap().try_exit_scope()
}
ScopeStatus::Current { zombie: true } => break self.exit_scope(),
ScopeStatus::Current { zombie: false } => {
panic!("active scope can't be dropped")
}
_ => unreachable!(),
}
}
}
fn exit_scope(&mut self) -> &mut Self {
self.scope_type_specific_data = Default::default();
self.status.set(ScopeStatus::Free);
let previous_nn = self.previous.unwrap();
self
.get_isolate_mut()
.set_current_scope_data(Some(previous_nn));
let previous_mut = unsafe { &mut *previous_nn.as_ptr() };
previous_mut.status.set(match previous_mut.status.get() {
ScopeStatus::Shadowed { zombie } => ScopeStatus::Current { zombie },
_ => unreachable!(),
});
previous_mut
}
pub(super) fn notify_scope_dropped(&mut self) {
match &self.scope_type_specific_data {
ScopeTypeSpecificData::HandleScope { .. }
| ScopeTypeSpecificData::EscapableHandleScope { .. } => {
self.status.set(match self.status.get() {
ScopeStatus::Current { zombie: false } => {
ScopeStatus::Current { zombie: true }
}
_ => unreachable!(),
})
}
_ => {
self.exit_scope();
}
}
}
pub(crate) fn get_isolate(&self) -> &Isolate {
unsafe { self.isolate.as_ref() }
}
pub(crate) fn get_isolate_mut(&mut self) -> &mut Isolate {
unsafe { self.isolate.as_mut() }
}
pub(crate) fn get_isolate_ptr(&self) -> *mut Isolate {
self.isolate.as_ptr()
}
pub(crate) fn get_current_context(&self) -> *const Context {
let get_current_context_from_isolate = || unsafe {
raw::v8__Isolate__GetCurrentContext(self.get_isolate_ptr())
};
match self.context.get().map(|nn| nn.as_ptr() as *const _) {
Some(context) => {
debug_assert!(unsafe {
raw::v8__Context__EQ(context, get_current_context_from_isolate())
});
context
}
None => {
let context = get_current_context_from_isolate();
self.context.set(NonNull::new(context as *mut _));
context
}
}
}
pub(super) fn get_escape_slot_mut(
&mut self,
) -> Option<&mut Option<raw::EscapeSlot>> {
self
.escape_slot
.as_mut()
.map(|escape_slot_nn| unsafe { escape_slot_nn.as_mut() })
}
pub(super) fn get_try_catch(&self) -> &raw::TryCatch {
self
.try_catch
.as_ref()
.map(|try_catch_nn| unsafe { try_catch_nn.as_ref() })
.unwrap()
}
pub(super) fn get_try_catch_mut(&mut self) -> &mut raw::TryCatch {
self
.try_catch
.as_mut()
.map(|try_catch_nn| unsafe { try_catch_nn.as_mut() })
.unwrap()
}
fn boxed(isolate: NonNull<Isolate>) -> Box<Self> {
unsafe {
#[allow(clippy::cast_ptr_alignment)]
let self_ptr = alloc(Layout::new::<Self>()) as *mut Self;
ptr::write(
self_ptr,
Self {
isolate,
previous: Default::default(),
next: Default::default(),
status: Default::default(),
context: Default::default(),
escape_slot: Default::default(),
try_catch: Default::default(),
scope_type_specific_data: Default::default(),
},
);
Box::from_raw(self_ptr)
}
}
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
enum ScopeStatus {
Free,
Current { zombie: bool },
Shadowed { zombie: bool },
}
impl Default for ScopeStatus {
fn default() -> Self {
Self::Free
}
}
#[derive(Debug)]
enum ScopeTypeSpecificData {
None,
ContextScope {
raw_context_scope: raw::ContextScope,
},
HandleScope {
raw_handle_scope: raw::HandleScope,
raw_context_scope: Option<raw::ContextScope>,
},
EscapableHandleScope {
raw_handle_scope: raw::HandleScope,
raw_escape_slot: Option<raw::EscapeSlot>,
},
TryCatch {
raw_try_catch: raw::TryCatch,
},
}
impl Default for ScopeTypeSpecificData {
fn default() -> Self {
Self::None
}
}
impl Drop for ScopeTypeSpecificData {
fn drop(&mut self) {
if let Self::HandleScope {
raw_context_scope, ..
} = self
{
*raw_context_scope = None
}
}
}
impl ScopeTypeSpecificData {
pub fn is_none(&self) -> bool {
matches!(self, Self::None)
}
pub fn init_with(&mut self, init_fn: impl FnOnce() -> Self) {
assert!(self.is_none());
unsafe { ptr::write(self, (init_fn)()) }
}
}
}
mod raw {
use super::*;
#[derive(Clone, Copy, Debug)]
#[repr(transparent)]
pub(super) struct Address(NonZeroUsize);
#[derive(Debug)]
pub(super) struct ContextScope {
entered_context: NonNull<Context>,
}
impl ContextScope {
pub fn new(context: Local<Context>) -> Self {
unsafe { v8__Context__Enter(&*context) };
Self {
entered_context: context.as_non_null(),
}
}
}
impl Drop for ContextScope {
fn drop(&mut self) {
unsafe { v8__Context__Exit(self.entered_context.as_ptr()) };
}
}
#[repr(C)]
#[derive(Debug)]
pub(super) struct HandleScope([usize; 3]);
impl HandleScope {
pub unsafe fn uninit() -> Self {
#[allow(clippy::uninit_assumed_init)]
Self(MaybeUninit::uninit().assume_init())
}
pub unsafe fn init(&mut self, isolate: NonNull<Isolate>) {
let buf = NonNull::from(self).cast();
v8__HandleScope__CONSTRUCT(buf.as_ptr(), isolate.as_ptr());
}
}
impl Drop for HandleScope {
fn drop(&mut self) {
unsafe { v8__HandleScope__DESTRUCT(self) };
}
}
#[repr(transparent)]
#[derive(Debug)]
pub(super) struct EscapeSlot(NonNull<raw::Address>);
impl EscapeSlot {
pub fn new(isolate: NonNull<Isolate>) -> Self {
unsafe {
let undefined = raw::v8__Undefined(isolate.as_ptr()) as *const _;
let local = raw::v8__Local__New(isolate.as_ptr(), undefined);
let slot_address_ptr = local as *const Address as *mut _;
let slot_address_nn = NonNull::new_unchecked(slot_address_ptr);
Self(slot_address_nn)
}
}
pub fn escape<'e, T>(self, value: Local<'_, T>) -> Local<'e, T>
where
for<'l> Local<'l, T>: Into<Local<'l, Data>>,
{
assert_eq!(Layout::new::<Self>(), Layout::new::<Local<T>>());
unsafe {
let undefined = Local::<Value>::from_non_null(self.0.cast());
debug_assert!(undefined.is_undefined());
let value_address = *(&*value as *const T as *const Address);
ptr::write(self.0.as_ptr(), value_address);
Local::from_non_null(self.0.cast())
}
}
}
#[repr(C)]
#[derive(Debug)]
pub(super) struct TryCatch([usize; 6]);
impl TryCatch {
pub unsafe fn uninit() -> Self {
#[allow(clippy::uninit_assumed_init)]
Self(MaybeUninit::uninit().assume_init())
}
pub unsafe fn init(&mut self, isolate: NonNull<Isolate>) {
let buf = NonNull::from(self).cast();
v8__TryCatch__CONSTRUCT(buf.as_ptr(), isolate.as_ptr());
}
}
impl Drop for TryCatch {
fn drop(&mut self) {
unsafe { v8__TryCatch__DESTRUCT(self) };
}
}
extern "C" {
pub(super) fn v8__Isolate__GetCurrentContext(
isolate: *mut Isolate,
) -> *const Context;
pub(super) fn v8__Isolate__GetEnteredOrMicrotaskContext(
isolate: *mut Isolate,
) -> *const Context;
pub(super) fn v8__Isolate__ThrowException(
isolate: *mut Isolate,
exception: *const Value,
) -> *const Value;
pub(super) fn v8__Isolate__GetDataFromSnapshotOnce(
this: *mut Isolate,
index: usize,
) -> *const Data;
pub(super) fn v8__Context__EQ(
this: *const Context,
other: *const Context,
) -> bool;
pub(super) fn v8__Context__Enter(this: *const Context);
pub(super) fn v8__Context__Exit(this: *const Context);
pub(super) fn v8__Context__GetIsolate(this: *const Context)
-> *mut Isolate;
pub(super) fn v8__Context__GetDataFromSnapshotOnce(
this: *const Context,
index: usize,
) -> *const Data;
pub(super) fn v8__HandleScope__CONSTRUCT(
buf: *mut MaybeUninit<HandleScope>,
isolate: *mut Isolate,
);
pub(super) fn v8__HandleScope__DESTRUCT(this: *mut HandleScope);
pub(super) fn v8__Local__New(
isolate: *mut Isolate,
other: *const Data,
) -> *const Data;
pub(super) fn v8__Undefined(isolate: *mut Isolate) -> *const Primitive;
pub(super) fn v8__TryCatch__CONSTRUCT(
buf: *mut MaybeUninit<TryCatch>,
isolate: *mut Isolate,
);
pub(super) fn v8__TryCatch__DESTRUCT(this: *mut TryCatch);
pub(super) fn v8__TryCatch__HasCaught(this: *const TryCatch) -> bool;
pub(super) fn v8__TryCatch__CanContinue(this: *const TryCatch) -> bool;
pub(super) fn v8__TryCatch__HasTerminated(this: *const TryCatch) -> bool;
pub(super) fn v8__TryCatch__IsVerbose(this: *const TryCatch) -> bool;
pub(super) fn v8__TryCatch__SetVerbose(this: *mut TryCatch, value: bool);
pub(super) fn v8__TryCatch__SetCaptureMessage(
this: *mut TryCatch,
value: bool,
);
pub(super) fn v8__TryCatch__Reset(this: *mut TryCatch);
pub(super) fn v8__TryCatch__Exception(
this: *const TryCatch,
) -> *const Value;
pub(super) fn v8__TryCatch__StackTrace(
this: *const TryCatch,
context: *const Context,
) -> *const Value;
pub(super) fn v8__TryCatch__Message(
this: *const TryCatch,
) -> *const Message;
pub(super) fn v8__TryCatch__ReThrow(this: *mut TryCatch) -> *const Value;
pub(super) fn v8__Message__GetIsolate(this: *const Message)
-> *mut Isolate;
pub(super) fn v8__Object__GetIsolate(this: *const Object) -> *mut Isolate;
pub(super) fn v8__FunctionCallbackInfo__GetIsolate(
this: *const FunctionCallbackInfo,
) -> *mut Isolate;
pub(super) fn v8__PropertyCallbackInfo__GetIsolate(
this: *const PropertyCallbackInfo,
) -> *mut Isolate;
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::new_default_platform;
use crate::Global;
use crate::V8;
use std::any::type_name;
use std::sync::Once;
trait SameType {}
impl<A> SameType for (A, A) {}
struct AssertTypeOf<'a, T>(pub &'a T);
impl<'a, T> AssertTypeOf<'a, T> {
pub fn is<A>(self)
where
(A, T): SameType,
{
assert_eq!(type_name::<A>(), type_name::<T>());
}
}
fn initialize_v8() {
static INIT: Once = Once::new();
INIT.call_once(|| {
V8::initialize_platform(new_default_platform().unwrap());
V8::initialize();
});
}
#[test]
fn deref_types() {
initialize_v8();
let isolate = &mut Isolate::new(Default::default());
AssertTypeOf(isolate).is::<OwnedIsolate>();
let l1_hs = &mut HandleScope::new(isolate);
AssertTypeOf(l1_hs).is::<HandleScope<()>>();
let context = Context::new(l1_hs);
{
let l2_cxs = &mut ContextScope::new(l1_hs, context);
AssertTypeOf(l2_cxs).is::<ContextScope<HandleScope>>();
{
let d = l2_cxs.deref_mut();
AssertTypeOf(d).is::<HandleScope>();
let d = d.deref_mut();
AssertTypeOf(d).is::<HandleScope<()>>();
let d = d.deref_mut();
AssertTypeOf(d).is::<Isolate>();
}
{
let l3_tc = &mut TryCatch::new(l2_cxs);
AssertTypeOf(l3_tc).is::<TryCatch<HandleScope>>();
let d = l3_tc.deref_mut();
AssertTypeOf(d).is::<HandleScope>();
let d = d.deref_mut();
AssertTypeOf(d).is::<HandleScope<()>>();
let d = d.deref_mut();
AssertTypeOf(d).is::<Isolate>();
}
{
let l3_ehs = &mut EscapableHandleScope::new(l2_cxs);
AssertTypeOf(l3_ehs).is::<EscapableHandleScope>();
{
let l4_cxs = &mut ContextScope::new(l3_ehs, context);
AssertTypeOf(l4_cxs).is::<ContextScope<EscapableHandleScope>>();
let d = l4_cxs.deref_mut();
AssertTypeOf(d).is::<EscapableHandleScope>();
let d = d.deref_mut();
AssertTypeOf(d).is::<HandleScope>();
let d = d.deref_mut();
AssertTypeOf(d).is::<HandleScope<()>>();
let d = d.deref_mut();
AssertTypeOf(d).is::<Isolate>();
}
{
let l4_tc = &mut TryCatch::new(l3_ehs);
AssertTypeOf(l4_tc).is::<TryCatch<EscapableHandleScope>>();
let d = l4_tc.deref_mut();
AssertTypeOf(d).is::<EscapableHandleScope>();
let d = d.deref_mut();
AssertTypeOf(d).is::<HandleScope>();
let d = d.deref_mut();
AssertTypeOf(d).is::<HandleScope<()>>();
let d = d.deref_mut();
AssertTypeOf(d).is::<Isolate>();
}
}
}
{
let l2_tc = &mut TryCatch::new(l1_hs);
AssertTypeOf(l2_tc).is::<TryCatch<HandleScope<()>>>();
let d = l2_tc.deref_mut();
AssertTypeOf(d).is::<HandleScope<()>>();
let d = d.deref_mut();
AssertTypeOf(d).is::<Isolate>();
}
{
let l2_ehs = &mut EscapableHandleScope::new(l1_hs);
AssertTypeOf(l2_ehs).is::<EscapableHandleScope<()>>();
let l3_tc = &mut TryCatch::new(l2_ehs);
AssertTypeOf(l3_tc).is::<TryCatch<EscapableHandleScope<()>>>();
let d = l3_tc.deref_mut();
AssertTypeOf(d).is::<EscapableHandleScope<()>>();
let d = d.deref_mut();
AssertTypeOf(d).is::<HandleScope<()>>();
let d = d.deref_mut();
AssertTypeOf(d).is::<Isolate>();
}
{
let _ = ContextScope::new(l1_hs, context);
let l2_cbs = &mut unsafe { CallbackScope::new(context) };
AssertTypeOf(l2_cbs).is::<CallbackScope>();
let d = l2_cbs.deref_mut();
AssertTypeOf(d).is::<HandleScope>();
let d = d.deref_mut();
AssertTypeOf(d).is::<HandleScope<()>>();
let d = d.deref_mut();
AssertTypeOf(d).is::<Isolate>();
}
{
let isolate: &mut Isolate = l1_hs.as_mut();
let l2_cbs = &mut unsafe { CallbackScope::new(isolate) };
AssertTypeOf(l2_cbs).is::<CallbackScope<()>>();
let d = l2_cbs.deref_mut();
AssertTypeOf(d).is::<HandleScope<()>>();
let d = d.deref_mut();
AssertTypeOf(d).is::<Isolate>();
}
}
#[test]
fn new_scope_types() {
initialize_v8();
let isolate = &mut Isolate::new(Default::default());
AssertTypeOf(isolate).is::<OwnedIsolate>();
let global_context: Global<Context>;
{
let l1_hs = &mut HandleScope::new(isolate);
AssertTypeOf(l1_hs).is::<HandleScope<()>>();
let context = Context::new(l1_hs);
global_context = Global::new(l1_hs, context);
AssertTypeOf(&HandleScope::new(l1_hs)).is::<HandleScope<()>>();
{
let l2_cxs = &mut ContextScope::new(l1_hs, context);
AssertTypeOf(l2_cxs).is::<ContextScope<HandleScope>>();
AssertTypeOf(&ContextScope::new(l2_cxs, context))
.is::<ContextScope<HandleScope>>();
AssertTypeOf(&HandleScope::new(l2_cxs)).is::<HandleScope>();
AssertTypeOf(&EscapableHandleScope::new(l2_cxs))
.is::<EscapableHandleScope>();
AssertTypeOf(&TryCatch::new(l2_cxs)).is::<TryCatch<HandleScope>>();
}
{
let l2_ehs = &mut EscapableHandleScope::new(l1_hs);
AssertTypeOf(l2_ehs).is::<EscapableHandleScope<()>>();
AssertTypeOf(&HandleScope::new(l2_ehs))
.is::<EscapableHandleScope<()>>();
AssertTypeOf(&EscapableHandleScope::new(l2_ehs))
.is::<EscapableHandleScope<()>>();
{
let l3_cxs = &mut ContextScope::new(l2_ehs, context);
AssertTypeOf(l3_cxs).is::<ContextScope<EscapableHandleScope>>();
AssertTypeOf(&ContextScope::new(l3_cxs, context))
.is::<ContextScope<EscapableHandleScope>>();
AssertTypeOf(&HandleScope::new(l3_cxs)).is::<EscapableHandleScope>();
AssertTypeOf(&EscapableHandleScope::new(l3_cxs))
.is::<EscapableHandleScope>();
{
let l4_tc = &mut TryCatch::new(l3_cxs);
AssertTypeOf(l4_tc).is::<TryCatch<EscapableHandleScope>>();
AssertTypeOf(&ContextScope::new(l4_tc, context))
.is::<ContextScope<EscapableHandleScope>>();
AssertTypeOf(&HandleScope::new(l4_tc)).is::<EscapableHandleScope>();
AssertTypeOf(&EscapableHandleScope::new(l4_tc))
.is::<EscapableHandleScope>();
AssertTypeOf(&TryCatch::new(l4_tc))
.is::<TryCatch<EscapableHandleScope>>();
}
}
{
let l3_tc = &mut TryCatch::new(l2_ehs);
AssertTypeOf(l3_tc).is::<TryCatch<EscapableHandleScope<()>>>();
AssertTypeOf(&ContextScope::new(l3_tc, context))
.is::<ContextScope<EscapableHandleScope>>();
AssertTypeOf(&HandleScope::new(l3_tc))
.is::<EscapableHandleScope<()>>();
AssertTypeOf(&EscapableHandleScope::new(l3_tc))
.is::<EscapableHandleScope<()>>();
AssertTypeOf(&TryCatch::new(l3_tc))
.is::<TryCatch<EscapableHandleScope<()>>>();
}
}
{
let l2_tc = &mut TryCatch::new(l1_hs);
AssertTypeOf(l2_tc).is::<TryCatch<HandleScope<()>>>();
AssertTypeOf(&ContextScope::new(l2_tc, context))
.is::<ContextScope<HandleScope>>();
AssertTypeOf(&HandleScope::new(l2_tc)).is::<HandleScope<()>>();
AssertTypeOf(&EscapableHandleScope::new(l2_tc))
.is::<EscapableHandleScope<()>>();
AssertTypeOf(&TryCatch::new(l2_tc)).is::<TryCatch<HandleScope<()>>>();
}
{
let l2_cbs = &mut unsafe { CallbackScope::new(context) };
AssertTypeOf(l2_cbs).is::<CallbackScope>();
AssertTypeOf(&ContextScope::new(l2_cbs, context))
.is::<ContextScope<HandleScope>>();
{
let l3_hs = &mut HandleScope::new(l2_cbs);
AssertTypeOf(l3_hs).is::<HandleScope>();
AssertTypeOf(&ContextScope::new(l3_hs, context))
.is::<ContextScope<HandleScope>>();
AssertTypeOf(&HandleScope::new(l3_hs)).is::<HandleScope>();
AssertTypeOf(&EscapableHandleScope::new(l3_hs))
.is::<EscapableHandleScope>();
AssertTypeOf(&TryCatch::new(l3_hs)).is::<TryCatch<HandleScope>>();
}
{
let l3_ehs = &mut EscapableHandleScope::new(l2_cbs);
AssertTypeOf(l3_ehs).is::<EscapableHandleScope>();
AssertTypeOf(&ContextScope::new(l3_ehs, context))
.is::<ContextScope<EscapableHandleScope>>();
AssertTypeOf(&HandleScope::new(l3_ehs)).is::<EscapableHandleScope>();
AssertTypeOf(&EscapableHandleScope::new(l3_ehs))
.is::<EscapableHandleScope>();
AssertTypeOf(&TryCatch::new(l3_ehs))
.is::<TryCatch<EscapableHandleScope>>();
}
{
let l3_tc = &mut TryCatch::new(l2_cbs);
AssertTypeOf(l3_tc).is::<TryCatch<HandleScope>>();
AssertTypeOf(&ContextScope::new(l3_tc, context))
.is::<ContextScope<HandleScope>>();
AssertTypeOf(&HandleScope::new(l3_tc)).is::<HandleScope>();
AssertTypeOf(&EscapableHandleScope::new(l3_tc))
.is::<EscapableHandleScope>();
AssertTypeOf(&TryCatch::new(l3_tc)).is::<TryCatch<HandleScope>>();
}
}
}
{
let l1_cbs = &mut unsafe { CallbackScope::new(&mut *isolate) };
AssertTypeOf(l1_cbs).is::<CallbackScope<()>>();
let context = Context::new(l1_cbs);
AssertTypeOf(&ContextScope::new(l1_cbs, context))
.is::<ContextScope<HandleScope>>();
AssertTypeOf(&HandleScope::new(l1_cbs)).is::<HandleScope<()>>();
AssertTypeOf(&EscapableHandleScope::new(l1_cbs))
.is::<EscapableHandleScope<()>>();
AssertTypeOf(&TryCatch::new(l1_cbs)).is::<TryCatch<HandleScope<()>>>();
}
{
AssertTypeOf(&HandleScope::with_context(isolate, &global_context))
.is::<HandleScope>();
AssertTypeOf(&HandleScope::with_context(isolate, global_context))
.is::<HandleScope>();
}
}
}