Skip to main content

v8/
scope.rs

1//! This module contains the rust wrappers for V8's scope types.
2//!
3//! There are two main types of scopes, with the other types being derived from them:
4//! - `HandleScope` - a scope to create and access `Local` handles
5//! - `TryCatch` - a scope to catch exceptions thrown from javascript
6//!
7//! There are a few important properties that make v8 scopes challenging to model in rust.
8//! - `HandleScope`s can (and almost certainly will be) nested, but handles are only
9//!   bound to the innermost `HandleScope`
10//!   - Importantly, this means that the Handle lifetimes are determined by the innermost `HandleScope`
11//! - Both `HandleScope` and `TryCatch`  cannot be moved, because V8 holds direct pointers to them
12//! - The C++ API relies heavily on inheritance, which is a bit awkward to model in rust
13//!
14//! # Example
15//!
16//! ```rust
17//! use v8::{HandleScope, Local, Object, Isolate, Context, ContextScope, Object};
18//! v8::V8::initialize();
19//!
20//! let scope = HandleScope::new(&mut isolate);
21//! let scope = std::pin::pin!(scope);
22//! let mut scope = scope.init();
23//! let context = Context::new(&scope, Default::default());
24//!
25//! let context_scope = ContextScope::new(&mut scope, context);
26//! let object = Object::new(&context_scope);
27//!
28//! ```
29//!
30//! ## Explanation
31//! The first thing you'll notice is that creating a `HandleScope` requires a few different steps. You'll see this pattern
32//! across all scope types that are address-sensitive (all except for `ContextScope`):
33//!
34//! 1. Allocate the storage for the scope. At this point, the scope is not yet address-sensitive, and so it can be safely moved.
35//! 2. Pin the storage to the stack. This is necessary because once we initialize the scope, it must not be moved.
36//! 3. Initialize the scope. This is where the scope is actually initialized, and our `Pin` ensures that the scope cannot be moved.
37//!
38//! This is a bit verbose, so you can collapse it into two lines,
39//! ```rust
40//! let scope = std::pin::pin!(HandleScope::new(&mut isolate));
41//! let mut scope = scope.init();
42//! ```
43//!
44//! or use the provided macros:
45//! ```rust
46//! // note that this expands into statements, introducing a new variable `scope` into the current
47//! // block. Using it as an expression (`let scope = v8::scope!(let scope, &mut isolate);`) will not work
48//! v8::scope!(let scope, &mut isolate);
49//! ```
50//!
51//! # Scopes as function args
52//! In a function that takes a scope, you'll typically want to take a `PinScope`, like
53//! ```rust
54//! fn foo<'s, 'i>(scope: &mut v8::PinScope<'s, 'i>) {
55//!   let local = v8::Number::new(scope, 42);
56//! }
57//! ```
58//!
59//! `PinScope` is just a shorthand for `PinnedRef<'s, HandleScope<'i>>`, which you can use if you really prefer.
60//!
61//! The lifetimes can sometimes be elided, but if you are taking or returning a `Local`, you'll need to specify at least the first one.
62//! ```
63//! fn foo<'s>(scope: &mut v8::PinScope<'s, '_>, arg: v8::Local<'s, v8::Number>) -> v8::Local<'s, v8::Number> {
64//!   v8::Number::new(scope, arg.value() + 42.0);
65//! }
66//! ```
67//!
68//! # Deref/DerefMut
69//!
70//! Scopes implement `Deref` and `DerefMut` to allow for sort of "inheritance" of behavior. This is useful because
71//! it allows most methods (as mentioned above) to just take a `PinScope`, and other scopes will deref to `PinScope`.
72//!
73//! That lets you seamlessly pass, for instance, a `ContextScope` to a function that takes a `PinScope`.
74//! Note that pinned scopes do not implement `Deref` or `DerefMut`, themselves, rather `PinnedRef` does.
75//!
76//! The deref implementations are:
77//!
78//! PinnedRef<'_, HandleScope<'_, ()>> -> Isolate
79//! PinnedRef<'_, HandleScope<'_>> -> PinnedRef<'_, HandleScope<'_, ()>>
80//! PinnedRef<'_, ContextScope<'_, '_>> -> PinnedRef<'_, HandleScope<'_>>
81//! PinnedRef<'_, CallbackScope<'_, '_>> -> PinnedRef<'_, HandleScope<'_, ()>>
82//!
83//!
84//!
85//! # Internals
86//!
87//! The initialization process uses the typestate pattern. The storage for the scope is a `ScopeStorage` struct, which is
88//! then transititions to a `Pin<&mut ScopeStorage<T>>`, and then `init` transitions to a `PinnedRef<'s, T>`.
89//!
90//! The `ScopeStorage` struct tracks initialization state, and is responsible for calling the destructor when the storage is dropped
91//! (iff the scope was initialized).
92//!
93//! The `PinnedRef` type, returned from `init`, is a transparent wrapper around a `Pin<&mut T>`. The reason it is a newtype is so
94//! that it can have specialized Deref/DerefMut implementations for the different scope types. `Pin` has a blanket implementation
95//! that doesn't have the behavior we want.
96//!
97//! ## Lifetimes
98//!
99//! The trickiest part of the scopes here are the lifetimes. In general, the lifetimes exist for a few reasons:
100//! - ensure that a scope can't outlive the thing it's made from (e.g. an isolate, or another scope)
101//! - ensure that a scope higher up the stack can't be used until the scope below it has dropped
102//! - ensure that the `Handle`s bound to the scope do not outlive the scope
103//!
104//! These lifetimes do not need to be exact, and in some cases I'm sure they are shorter than they could be,
105//! as long as everything lives long enough. In other words, the lifetimes just need to be a safe approximation.
106//!
107//!
108//! ### HandleScope
109//! `HandleScope` itself has only one lifetime, `'i` which is the lifetime of the thing that the scope was created from
110//! (e.g. an isolate).
111//!
112//! The lifetime for handles bound to the scope is really the lifetime of the `HandleScope` itself. In our case,
113//! since we've pinned it to the stack, that is the lifetime of the pinned reference. So in
114//! `PinnedRef<'s, HandleScope<'i>>`, `'s` is the lifetime of the pinned reference, and therefore
115//! the handles, and 'i is the lifetime of the isolate.
116//!
117//! ### ContextScope
118//! ContextScope is really just a wrapper around another scope, with a `Context` added to it.
119//! It wraps a scope, and so it is not actually address-sensitive, and can be moved around freely.
120//!
121//! ContextScope has two lifetimes, `'b` and `'s`. `'b` is the lifetime of the borrow of the scope
122//! it's wrapping, and `'s` is the lifetime of the scope.
123//!
124//! Effectively you have `&'b PinnedRef<'s, T>`.
125//!
126//! The lifetime for handles bound to the scope is the lifetime of the scope that it was created from.
127//! So in `ContextScope<'b, 's>`, `'b` is the lifetime of the borrow of the inner scope, and `'s` is the lifetime of the inner scope (and therefore the handles).
128use crate::{
129  Context, Data, DataError, Function, FunctionCallbackInfo, Isolate, Local,
130  Message, Object, OwnedIsolate, PromiseRejectMessage, PropertyCallbackInfo,
131  SealedLocal, Value, fast_api::FastApiCallbackOptions, isolate::RealIsolate,
132  support::assert_layout_subset,
133};
134use std::{
135  any::type_name,
136  cell::Cell,
137  marker::{PhantomData, PhantomPinned},
138  mem::ManuallyDrop,
139  ops::{Deref, DerefMut},
140  pin::Pin,
141  ptr::NonNull,
142};
143pub(crate) mod raw;
144
145pub type PinScope<'s, 'i, C = Context> = PinnedRef<'s, HandleScope<'i, C>>;
146pub type PinCallbackScope<'s, 'i, C = Context> =
147  PinnedRef<'s, CallbackScope<'i, C>>;
148
149/// Storage for a scope.
150///
151/// Tracks the initialization state of the scope, and holds the scope itself.
152#[repr(C)]
153pub struct ScopeStorage<T: ScopeInit> {
154  inited: bool,
155  scope: ManuallyDrop<T>,
156  _pinned: PhantomPinned,
157}
158
159impl<T: ScopeInit> ScopeStorage<T> {
160  pub(crate) fn projected(self: Pin<&mut Self>) -> Pin<&mut T> {
161    // SAFETY: we are just projecting to a field, so the scope remains pinned
162    unsafe {
163      let self_mut = self.get_unchecked_mut();
164      Pin::new_unchecked(&mut self_mut.scope)
165    }
166  }
167
168  pub fn new(scope: T) -> Self {
169    Self {
170      inited: false,
171      scope: ManuallyDrop::new(scope),
172      _pinned: PhantomPinned,
173    }
174  }
175
176  pub fn init(mut self: Pin<&mut Self>) -> PinnedRef<'_, T> {
177    if self.inited {
178      // free old, going to reuse this storage
179      unsafe {
180        let self_mut = self.as_mut().get_unchecked_mut();
181        self_mut.drop_inner();
182        self_mut.inited = false;
183      }
184    }
185
186    // hold onto a pointer so we can set this after initialization. we can't use a normal
187    // mutable reference because the borrow checker will see overlapping borrows. this is
188    // safe, however, because we lose our mutable reference to the storage in `init_stack`
189    // as it gets projected to the inner type
190    let inited_ptr =
191      unsafe { &raw mut self.as_mut().get_unchecked_mut().inited };
192    let ret = T::init_stack(self);
193    unsafe { inited_ptr.write(true) };
194    PinnedRef(ret)
195  }
196
197  /// SAFEFTY: `self.inited` must be true, and therefore must be pinned
198  unsafe fn drop_inner(&mut self) {
199    unsafe {
200      T::deinit(&mut self.scope);
201    }
202    self.inited = false;
203  }
204}
205
206impl<T: ScopeInit> Drop for ScopeStorage<T> {
207  fn drop(&mut self) {
208    if self.inited {
209      unsafe {
210        self.drop_inner();
211      }
212    }
213  }
214}
215
216pub trait Scope: Sized + sealed::Sealed + ScopeInit {}
217
218mod sealed {
219  pub trait Sealed {}
220}
221
222pub trait ScopeInit: Sized {
223  fn init_stack(storage: Pin<&mut ScopeStorage<Self>>) -> Pin<&mut Self>;
224
225  unsafe fn deinit(me: &mut Self);
226}
227
228impl<C> ScopeInit for HandleScope<'_, C> {
229  fn init_stack(storage: Pin<&mut ScopeStorage<Self>>) -> Pin<&mut Self> {
230    // SAFETY: no moving the scope from this point on
231    let storage_mut = unsafe { storage.get_unchecked_mut() };
232    unsafe {
233      let isolate = storage_mut.scope.isolate;
234      raw::HandleScope::init(&mut storage_mut.scope.raw_handle_scope, isolate)
235    };
236
237    let projected = &mut storage_mut.scope;
238
239    // SAFETY: scope is still pinned
240    unsafe { Pin::new_unchecked(projected) }
241  }
242
243  unsafe fn deinit(me: &mut Self) {
244    unsafe { raw::v8__HandleScope__DESTRUCT(&mut me.raw_handle_scope) };
245  }
246}
247
248/// A stack-allocated class that governs a number of local handles.
249/// After a handle scope has been created, all local handles will be
250/// allocated within that handle scope until either the handle scope is
251/// deleted or another handle scope is created.  If there is already a
252/// handle scope and a new one is created, all allocations will take
253/// place in the new handle scope until it is deleted.  After that,
254/// new handles will again be allocated in the original handle scope.
255///
256/// After the handle scope of a local handle has been deleted the
257/// garbage collector will no longer track the object stored in the
258/// handle and may deallocate it.  The behavior of accessing a handle
259/// for which the handle scope has been deleted is undefined.
260#[repr(C)]
261#[derive(Debug)]
262pub struct HandleScope<'s, C = Context> {
263  raw_handle_scope: raw::HandleScope,
264  isolate: NonNull<RealIsolate>,
265  context: Cell<Option<NonNull<Context>>>,
266  _phantom: PhantomData<&'s mut C>,
267  _pinned: PhantomPinned,
268}
269
270impl<C> sealed::Sealed for HandleScope<'_, C> {}
271impl<C> Scope for HandleScope<'_, C> {}
272
273mod get_isolate {
274  use crate::RealIsolate;
275  pub trait GetIsolate {
276    fn get_isolate_ptr(&self) -> *mut RealIsolate;
277  }
278}
279pub(crate) use get_isolate::GetIsolate;
280
281mod get_isolate_impls {
282  use crate::{Promise, PromiseRejectMessage};
283
284  use super::*;
285  impl GetIsolate for Isolate {
286    fn get_isolate_ptr(&self) -> *mut RealIsolate {
287      self.as_real_ptr()
288    }
289  }
290
291  impl GetIsolate for OwnedIsolate {
292    fn get_isolate_ptr(&self) -> *mut RealIsolate {
293      self.as_real_ptr()
294    }
295  }
296
297  impl GetIsolate for FunctionCallbackInfo {
298    fn get_isolate_ptr(&self) -> *mut RealIsolate {
299      self.get_isolate_ptr()
300    }
301  }
302
303  impl<T> GetIsolate for PropertyCallbackInfo<T> {
304    fn get_isolate_ptr(&self) -> *mut RealIsolate {
305      self.get_isolate_ptr()
306    }
307  }
308
309  impl GetIsolate for FastApiCallbackOptions<'_> {
310    fn get_isolate_ptr(&self) -> *mut RealIsolate {
311      self.isolate
312    }
313  }
314
315  impl GetIsolate for Local<'_, Context> {
316    fn get_isolate_ptr(&self) -> *mut RealIsolate {
317      unsafe { raw::v8__Isolate__GetCurrent() }
318    }
319  }
320
321  impl GetIsolate for Local<'_, Message> {
322    fn get_isolate_ptr(&self) -> *mut RealIsolate {
323      unsafe { raw::v8__Isolate__GetCurrent() }
324    }
325  }
326
327  impl GetIsolate for Local<'_, Promise> {
328    fn get_isolate_ptr(&self) -> *mut RealIsolate {
329      unsafe { raw::v8__Isolate__GetCurrent() }
330    }
331  }
332
333  impl GetIsolate for PromiseRejectMessage<'_> {
334    fn get_isolate_ptr(&self) -> *mut RealIsolate {
335      unsafe { raw::v8__Isolate__GetCurrent() }
336    }
337  }
338
339  impl<C> GetIsolate for HandleScope<'_, C> {
340    fn get_isolate_ptr(&self) -> *mut RealIsolate {
341      self.isolate.as_ptr()
342    }
343  }
344
345  impl<P: GetIsolate + ClearCachedContext> GetIsolate
346    for ContextScope<'_, '_, P>
347  {
348    fn get_isolate_ptr(&self) -> *mut RealIsolate {
349      self.scope.get_isolate_ptr()
350    }
351  }
352
353  impl<P: GetIsolate> GetIsolate for &mut P {
354    fn get_isolate_ptr(&self) -> *mut RealIsolate {
355      P::get_isolate_ptr(self)
356    }
357  }
358
359  impl<P: GetIsolate> GetIsolate for &P {
360    fn get_isolate_ptr(&self) -> *mut RealIsolate {
361      P::get_isolate_ptr(self)
362    }
363  }
364
365  impl<P: GetIsolate> GetIsolate for TryCatch<'_, '_, P> {
366    fn get_isolate_ptr(&self) -> *mut RealIsolate {
367      self.scope.get_isolate_ptr()
368    }
369  }
370
371  impl<C> GetIsolate for CallbackScope<'_, C> {
372    fn get_isolate_ptr(&self) -> *mut RealIsolate {
373      self.isolate.as_ptr()
374    }
375  }
376
377  impl<C> GetIsolate for EscapableHandleScope<'_, '_, C> {
378    fn get_isolate_ptr(&self) -> *mut RealIsolate {
379      self.isolate.as_ptr()
380    }
381  }
382
383  impl<P: GetIsolate> GetIsolate for AllowJavascriptExecutionScope<'_, '_, P> {
384    fn get_isolate_ptr(&self) -> *mut RealIsolate {
385      self.scope.get_isolate_ptr()
386    }
387  }
388
389  impl<P: GetIsolate> GetIsolate for DisallowJavascriptExecutionScope<'_, '_, P> {
390    fn get_isolate_ptr(&self) -> *mut RealIsolate {
391      self.scope.get_isolate_ptr()
392    }
393  }
394}
395
396pub trait NewHandleScope<'s> {
397  type NewScope: Scope;
398
399  fn make_new_scope(me: &'s mut Self) -> Self::NewScope;
400}
401
402impl<'s, 'p: 's, C> NewHandleScope<'s> for PinnedRef<'_, HandleScope<'p, C>> {
403  type NewScope = HandleScope<'s, C>;
404
405  fn make_new_scope(me: &'s mut Self) -> Self::NewScope {
406    HandleScope {
407      raw_handle_scope: unsafe { raw::HandleScope::uninit() },
408      isolate: me.0.isolate,
409      context: Cell::new(me.0.context.get()),
410      _phantom: PhantomData,
411      _pinned: PhantomPinned,
412    }
413  }
414}
415
416impl<'s> NewHandleScope<'s> for Isolate {
417  type NewScope = HandleScope<'s, ()>;
418
419  #[inline(always)]
420  fn make_new_scope(me: &'s mut Self) -> Self::NewScope {
421    HandleScope {
422      raw_handle_scope: unsafe { raw::HandleScope::uninit() },
423      isolate: unsafe { NonNull::new_unchecked(me.as_real_ptr()) },
424      context: Cell::new(None),
425      _phantom: PhantomData,
426      _pinned: PhantomPinned,
427    }
428  }
429}
430
431impl<'s> NewHandleScope<'s> for OwnedIsolate {
432  type NewScope = HandleScope<'s, ()>;
433
434  fn make_new_scope(me: &'s mut Self) -> Self::NewScope {
435    HandleScope {
436      raw_handle_scope: unsafe { raw::HandleScope::uninit() },
437      isolate: unsafe { NonNull::new_unchecked(me.get_isolate_ptr()) },
438      context: Cell::new(None),
439      _phantom: PhantomData,
440      _pinned: PhantomPinned,
441    }
442  }
443}
444
445impl<'s, 'p: 's, 'i, C> NewHandleScope<'s>
446  for PinnedRef<'p, CallbackScope<'i, C>>
447{
448  type NewScope = HandleScope<'i, C>;
449
450  fn make_new_scope(me: &'s mut Self) -> Self::NewScope {
451    HandleScope {
452      raw_handle_scope: unsafe { raw::HandleScope::uninit() },
453      isolate: me.0.isolate,
454      context: Cell::new(me.0.context.get()),
455      _phantom: PhantomData,
456      _pinned: PhantomPinned,
457    }
458  }
459}
460
461impl<'a, 'i> NewHandleScope<'a> for ContextScope<'_, '_, HandleScope<'i>> {
462  type NewScope = HandleScope<'i>;
463  fn make_new_scope(me: &'a mut Self) -> Self::NewScope {
464    HandleScope {
465      raw_handle_scope: unsafe { raw::HandleScope::uninit() },
466      isolate: unsafe { NonNull::new_unchecked(me.scope.get_isolate_ptr()) },
467      context: Cell::new(Some(me.raw_handle_scope.entered_context)),
468      _phantom: PhantomData,
469      _pinned: PhantomPinned,
470    }
471  }
472}
473
474pub(crate) struct ScopeData {
475  isolate: NonNull<RealIsolate>,
476  context: Cell<Option<NonNull<Context>>>,
477}
478
479impl ScopeData {
480  #[inline(always)]
481  pub(crate) fn get_isolate_ptr(&self) -> *mut RealIsolate {
482    self.isolate.as_ptr()
483  }
484
485  pub(crate) fn get_current_context(&self) -> *mut Context {
486    if let Some(context) = self.context.get() {
487      context.as_ptr()
488    } else {
489      let isolate = self.get_isolate_ptr();
490      let context =
491        unsafe { raw::v8__Isolate__GetCurrentContext(isolate) }.cast_mut();
492      self
493        .context
494        .set(Some(unsafe { NonNull::new_unchecked(context) }));
495      context
496    }
497  }
498}
499
500impl<'s> HandleScope<'s> {
501  #[allow(clippy::new_ret_no_self)]
502  pub fn new<P: NewHandleScope<'s>>(
503    scope: &'s mut P,
504  ) -> ScopeStorage<P::NewScope> {
505    ScopeStorage::new(P::make_new_scope(scope))
506  }
507}
508
509impl<'s> PinnedRef<'s, HandleScope<'_>> {
510  /// Returns the context of the currently running JavaScript, or the context
511  /// on the top of the stack if no JavaScript is running
512  pub fn get_current_context(&self) -> Local<'s, Context> {
513    if let Some(context) = self.0.context.get() {
514      unsafe { Local::from_non_null(context) }
515    } else {
516      let isolate = self.0.isolate;
517      let context =
518        unsafe { raw::v8__Isolate__GetCurrentContext(isolate.as_ptr()) }
519          .cast_mut();
520      unsafe {
521        self.0.context.set(Some(NonNull::new_unchecked(context)));
522        Local::from_raw_unchecked(context)
523      }
524    }
525  }
526
527  /// Returns either the last context entered through V8's C++ API, or the
528  /// context of the currently running microtask while processing microtasks.
529  /// If a context is entered while executing a microtask, that context is
530  /// returned.
531  pub fn get_entered_or_microtask_context(&self) -> Local<'_, Context> {
532    let context_ptr = unsafe {
533      raw::v8__Isolate__GetEnteredOrMicrotaskContext(self.0.isolate.as_ptr())
534    };
535    unsafe { Local::from_raw_unchecked(context_ptr) }
536  }
537
538  /// Return data that was previously attached to the isolate snapshot via
539  /// SnapshotCreator, and removes the reference to it. If called again with
540  /// same `index` argument, this function returns `DataError::NoData`.
541  ///
542  /// The value that was stored in the snapshot must either match or be
543  /// convertible to type parameter `T`, otherwise `DataError::BadType` is
544  /// returned.
545  pub fn get_isolate_data_from_snapshot_once<T>(
546    &self,
547    index: usize,
548  ) -> Result<Local<'s, T>, DataError>
549  where
550    T: 'static,
551    for<'l> <Local<'l, Data> as TryInto<Local<'l, T>>>::Error:
552      get_data_sealed::ToDataError,
553    for<'l> Local<'l, Data>: TryInto<Local<'l, T>>,
554  {
555    unsafe {
556      let Some(res) = self.cast_local(|sd| {
557        raw::v8__Isolate__GetDataFromSnapshotOnce(sd.get_isolate_ptr(), index)
558      }) else {
559        return Err(DataError::no_data::<T>());
560      };
561      use get_data_sealed::ToDataError;
562      match res.try_into() {
563        Ok(x) => Ok(x),
564        Err(e) => Err(e.to_data_error()),
565      }
566    }
567  }
568
569  /// Return data that was previously attached to the context snapshot via
570  /// SnapshotCreator, and removes the reference to it. If called again with
571  /// same `index` argument, this function returns `DataError::NoData`.
572  ///
573  /// The value that was stored in the snapshot must either match or be
574  /// convertible to type parameter `T`, otherwise `DataError::BadType` is
575  /// returned.
576  pub fn get_context_data_from_snapshot_once<T>(
577    &self,
578    index: usize,
579  ) -> Result<Local<'s, T>, DataError>
580  where
581    T: 'static,
582    for<'l> <Local<'l, Data> as TryInto<Local<'l, T>>>::Error:
583      get_data_sealed::ToDataError,
584    for<'l> Local<'l, Data>: TryInto<Local<'l, T>>,
585  {
586    unsafe {
587      let Some(res) = self.cast_local(|sd| {
588        raw::v8__Context__GetDataFromSnapshotOnce(
589          sd.get_current_context(),
590          index,
591        )
592      }) else {
593        return Err(DataError::no_data::<T>());
594      };
595      use get_data_sealed::ToDataError;
596      match res.try_into() {
597        Ok(x) => Ok(x),
598        Err(e) => Err(e.to_data_error()),
599      }
600    }
601  }
602
603  #[inline(always)]
604  pub fn set_promise_hooks(
605    &self,
606    init_hook: Option<Local<Function>>,
607    before_hook: Option<Local<Function>>,
608    after_hook: Option<Local<Function>>,
609    resolve_hook: Option<Local<Function>>,
610  ) {
611    unsafe {
612      let context = self.get_current_context();
613      raw::v8__Context__SetPromiseHooks(
614        context.as_non_null().as_ptr(),
615        init_hook.map_or_else(std::ptr::null, |v| &*v),
616        before_hook.map_or_else(std::ptr::null, |v| &*v),
617        after_hook.map_or_else(std::ptr::null, |v| &*v),
618        resolve_hook.map_or_else(std::ptr::null, |v| &*v),
619      );
620    }
621  }
622
623  #[inline(always)]
624  pub fn set_continuation_preserved_embedder_data(&self, data: Local<Value>) {
625    unsafe {
626      let isolate = self.0.isolate;
627      raw::v8__Context__SetContinuationPreservedEmbedderData(
628        isolate.as_ptr(),
629        &*data,
630      );
631    }
632  }
633
634  #[inline(always)]
635  pub fn get_continuation_preserved_embedder_data(&self) -> Local<'s, Value> {
636    unsafe {
637      self
638        .cast_local(|sd| {
639          raw::v8__Context__GetContinuationPreservedEmbedderData(
640            sd.get_isolate_ptr(),
641          )
642        })
643        .unwrap()
644    }
645  }
646
647  /// Returns the host defined options set for currently running script or
648  /// module, if available.
649  #[inline(always)]
650  pub fn get_current_host_defined_options(&self) -> Option<Local<'s, Data>> {
651    let isolate_ptr = self.0.isolate.as_ptr();
652    unsafe {
653      Local::from_raw(raw::v8__Isolate__GetCurrentHostDefinedOptions(
654        isolate_ptr,
655      ))
656    }
657  }
658}
659
660// for<'l> DataError: From<<Local<'s, Data> as TryInto<Local<'l, T>>>::Error>,
661mod get_data_sealed {
662  use crate::DataError;
663  use std::convert::Infallible;
664
665  pub trait ToDataError {
666    fn to_data_error(self) -> DataError;
667  }
668  impl ToDataError for DataError {
669    fn to_data_error(self) -> DataError {
670      self
671    }
672  }
673  impl ToDataError for Infallible {
674    fn to_data_error(self) -> DataError {
675      unreachable!()
676    }
677  }
678}
679
680impl<'p> PinnedRef<'p, HandleScope<'_, ()>> {
681  #[inline(always)]
682  pub(crate) unsafe fn cast_local<T>(
683    &self,
684    _f: impl FnOnce(&mut ScopeData) -> *const T,
685  ) -> Option<Local<'p, T>> {
686    let mut data: ScopeData = ScopeData {
687      context: Cell::new(self.0.context.get()),
688      isolate: self.0.isolate,
689    };
690    let ptr = _f(&mut data);
691    unsafe { Local::from_raw(ptr) }
692  }
693
694  /// Schedules an exception to be thrown when returning to JavaScript. When
695  /// an exception has been scheduled it is illegal to invoke any
696  /// JavaScript operation; the caller must return immediately and only
697  /// after the exception has been handled does it become legal to invoke
698  /// JavaScript operations.
699  ///
700  /// This function always returns the `undefined` value.
701  pub fn throw_exception(
702    &self,
703    exception: Local<'p, Value>,
704  ) -> Local<'p, Value> {
705    unsafe {
706      self.cast_local(|sd| {
707        raw::v8__Isolate__ThrowException(sd.get_isolate_ptr(), &*exception)
708      })
709    }
710    .unwrap()
711  }
712
713  /// Open a handle passed from V8 in the current scope.
714  ///
715  /// # Safety
716  ///
717  /// The handle must be rooted in this scope.
718  #[inline(always)]
719  pub unsafe fn unseal<'a, T>(&self, v: SealedLocal<T>) -> Local<'a, T> {
720    unsafe { Local::from_non_null(v.0) }
721  }
722}
723
724impl<C> HandleScope<'_, C> {}
725
726impl<C> GetIsolate for Pin<&mut HandleScope<'_, C>> {
727  fn get_isolate_ptr(&self) -> *mut RealIsolate {
728    self.isolate.as_ptr()
729  }
730}
731
732/// Stack-allocated class which sets the execution context for all operations
733/// executed within a local scope. After entering a context, all code compiled
734/// and run is compiled and run in this context.
735#[repr(C)]
736pub struct ContextScope<'borrow, 'scope, P: ClearCachedContext> {
737  raw_handle_scope: raw::ContextScope,
738  scope: &'borrow mut PinnedRef<'scope, P>,
739}
740
741impl<P: ClearCachedContext> ScopeInit for ContextScope<'_, '_, P> {
742  fn init_stack(storage: Pin<&mut ScopeStorage<Self>>) -> Pin<&mut Self> {
743    storage.projected()
744  }
745  unsafe fn deinit(_me: &mut Self) {}
746}
747
748impl<'p, P: ClearCachedContext> Deref for ContextScope<'_, 'p, P> {
749  type Target = PinnedRef<'p, P>;
750  fn deref(&self) -> &Self::Target {
751    self.scope
752  }
753}
754
755impl<P: ClearCachedContext> DerefMut for ContextScope<'_, '_, P> {
756  fn deref_mut(&mut self) -> &mut Self::Target {
757    self.scope
758  }
759}
760
761impl<P: ClearCachedContext> sealed::Sealed for ContextScope<'_, '_, P> {}
762impl<P: ClearCachedContext> Scope for ContextScope<'_, '_, P> {}
763
764mod new_context_scope {
765
766  use super::{GetIsolate, Scope};
767  use crate::{Context, Local};
768
769  pub trait NewContextScope<'s, 'c>: GetIsolate {
770    type NewScope: Scope;
771
772    fn make_new_scope(
773      me: &'s mut Self,
774      context: Local<'c, Context>,
775    ) -> Self::NewScope;
776  }
777}
778use new_context_scope::NewContextScope;
779
780mod clear_cached_context {
781  pub trait ClearCachedContext {
782    fn clear_cached_context(&self);
783  }
784}
785use clear_cached_context::ClearCachedContext;
786
787impl<C> ClearCachedContext for HandleScope<'_, C> {
788  fn clear_cached_context(&self) {
789    self.context.set(None);
790  }
791}
792
793impl<C> ClearCachedContext for CallbackScope<'_, C> {
794  fn clear_cached_context(&self) {}
795}
796
797impl<P: ClearCachedContext> ClearCachedContext for PinnedRef<'_, P> {
798  fn clear_cached_context(&self) {
799    self.0.clear_cached_context();
800  }
801}
802
803impl<C> ClearCachedContext for EscapableHandleScope<'_, '_, C> {
804  fn clear_cached_context(&self) {
805    self.context.set(None);
806  }
807}
808
809impl<P> Drop for ContextScope<'_, '_, P>
810where
811  P: ClearCachedContext,
812{
813  fn drop(&mut self) {
814    self.scope.0.clear_cached_context();
815  }
816}
817
818impl<'scope, 'obj: 'scope, 'ct, P: Scope + GetIsolate>
819  NewContextScope<'scope, 'ct> for ContextScope<'_, 'obj, P>
820where
821  P: ClearCachedContext,
822{
823  type NewScope = ContextScope<'scope, 'obj, P>;
824
825  fn make_new_scope(
826    me: &'scope mut Self,
827    context: Local<'ct, Context>,
828  ) -> Self::NewScope {
829    ContextScope {
830      raw_handle_scope: raw::ContextScope::new(context),
831      scope: me.scope,
832    }
833  }
834}
835
836impl<'scope, 'obj: 'scope, 'ct, 'i, C> NewContextScope<'scope, 'ct>
837  for PinnedRef<'obj, HandleScope<'i, C>>
838where
839  'ct: 'scope,
840{
841  type NewScope = ContextScope<'scope, 'obj, HandleScope<'i>>;
842
843  fn make_new_scope(
844    me: &'scope mut Self,
845    context: Local<'ct, Context>,
846  ) -> Self::NewScope {
847    me.0.context.set(None);
848    ContextScope {
849      raw_handle_scope: raw::ContextScope::new(context),
850      scope: unsafe {
851        // SAFETY: we are adding the context, so we can mark that it now has a context.
852        // the types are the same aside from the type parameter, which is only used in a ZST
853        cast_pinned_ref_mut::<HandleScope<'i, C>, HandleScope<'i, Context>>(me)
854      },
855    }
856  }
857}
858
859impl<'scope, 'obj: 'scope, 'i, 'ct, C> NewContextScope<'scope, 'ct>
860  for PinnedRef<'obj, CallbackScope<'i, C>>
861{
862  type NewScope = ContextScope<'scope, 'obj, HandleScope<'i>>;
863
864  fn make_new_scope(
865    me: &'scope mut Self,
866    context: Local<'ct, Context>,
867  ) -> Self::NewScope {
868    ContextScope {
869      raw_handle_scope: raw::ContextScope::new(context),
870      scope: unsafe {
871        // we are adding the context, so we can mark that it now has a context.
872        // SAFETY: CallbackScope is a superset of HandleScope, so giving a "view" of
873        // the CallbackScope as a HandleScope is valid, and we won't ever move out of the transmuted
874        // value
875        cast_pinned_ref_mut::<CallbackScope<'i, C>, HandleScope<'i, Context>>(
876          me,
877        )
878      },
879    }
880  }
881}
882
883// these lifetimes are crazy. basically we have
884// - 'borrow: the borrow of the scope
885// - 'scope: the lifetime of the scope. this must be longer than 'borrow. this is the lifetime of the handles created from the scope.
886// - 'i: the lifetime of the inner the `EscapableHandleScope` is made from
887// - 'esc: the lifetime of the slot that the `EscapableHandleScope` will eventually escape to. this must be longer than 'i
888// - 'ct: the lifetime of the context (this is _not_ the same as 'scope, it can be longer or shorter)
889impl<'borrow, 'scope: 'borrow, 'i, 'esc: 'i, 'ct, C>
890  NewContextScope<'borrow, 'ct>
891  for PinnedRef<'scope, EscapableHandleScope<'i, 'esc, C>>
892{
893  type NewScope = ContextScope<'borrow, 'scope, EscapableHandleScope<'i, 'esc>>;
894
895  fn make_new_scope(
896    me: &'borrow mut Self,
897    context: Local<'ct, Context>,
898  ) -> Self::NewScope {
899    ContextScope {
900      raw_handle_scope: raw::ContextScope::new(context),
901      scope: unsafe {
902        // SAFETY: layouts are the same aside from the type parameter, which is only used in a ZST
903        std::mem::transmute::<
904          &'borrow mut PinnedRef<'scope, EscapableHandleScope<'i, 'esc, C>>,
905          &'borrow mut PinnedRef<
906            'scope,
907            EscapableHandleScope<'i, 'esc, Context>,
908          >,
909        >(me)
910      },
911    }
912  }
913}
914
915impl<P: ClearCachedContext> ClearCachedContext for ContextScope<'_, '_, P> {
916  fn clear_cached_context(&self) {
917    self.scope.0.clear_cached_context();
918  }
919}
920
921impl<
922  'scope,
923  'obj: 'scope,
924  'ct,
925  P: NewContextScope<'scope, 'ct> + ClearCachedContext,
926> ContextScope<'scope, 'obj, P>
927{
928  #[allow(clippy::new_ret_no_self)]
929  pub fn new(
930    param: &'scope mut P,
931    context: Local<'ct, Context>,
932  ) -> P::NewScope {
933    if param.get_isolate_ptr() != unsafe { raw::v8__Isolate__GetCurrent() } {
934      panic!(
935        "{} and Context do not belong to the same Isolate",
936        type_name::<P>()
937      )
938    }
939    param.clear_cached_context();
940    P::make_new_scope(param, context)
941  }
942}
943
944/// A `CallbackScope` can be used to bootstrap a `HandleScope` and
945/// `ContextScope` inside a callback function that gets called by V8.
946/// Bootstrapping a scope inside a callback is the only valid use case of this
947/// type; using it in other places leads to undefined behavior, which is also
948/// the reason `CallbackScope::new()` is marked as being an unsafe function.
949///
950/// For some callback types, rusty_v8 internally creates a scope and passes it
951/// as an argument to to embedder callback. Eventually we intend to wrap all
952/// callbacks in this fashion, so the embedder would never needs to construct
953/// a CallbackScope.
954///
955/// A `CallbackScope<()>`, without context, can be created from:
956///   - `&mut Isolate`
957///   - `&mut OwnedIsolate`
958///
959/// A `CallbackScope`, with context, can be created from:
960///   - `Local<Context>`
961///   - `Local<Message>`
962///   - `Local<Object>`
963///   - `Local<Promise>`
964///   - `Local<SharedArrayBuffer>`
965///   - `&FunctionCallbackInfo`
966///   - `&PropertyCallbackInfo`
967///   - `&PromiseRejectMessage`
968///   - `&FastApiCallbackOptions`
969#[repr(C)]
970#[derive(Debug)]
971pub struct CallbackScope<'s, C = Context> {
972  raw_handle_scope: raw::HandleScope,
973  isolate: NonNull<RealIsolate>,
974  context: Cell<Option<NonNull<Context>>>,
975  _phantom: PhantomData<&'s C>,
976  _pinned: PhantomPinned,
977  needs_scope: bool,
978}
979
980assert_layout_subset!(HandleScope<'static, ()>, CallbackScope<'static, ()> { raw_handle_scope, isolate, context, _phantom, _pinned });
981
982impl<'s> CallbackScope<'s> {
983  #[allow(clippy::new_ret_no_self)]
984  pub unsafe fn new<P: NewCallbackScope<'s>>(
985    param: P,
986  ) -> ScopeStorage<P::NewScope> {
987    ScopeStorage::new(P::make_new_scope(param))
988  }
989}
990
991impl<C> AsRef<Isolate> for CallbackScope<'_, C> {
992  fn as_ref(&self) -> &Isolate {
993    unsafe { Isolate::from_raw_ref(&self.isolate) }
994  }
995}
996
997impl<C> ScopeInit for CallbackScope<'_, C> {
998  fn init_stack(storage: Pin<&mut ScopeStorage<Self>>) -> Pin<&mut Self> {
999    let storage_mut = unsafe { storage.get_unchecked_mut() };
1000    let isolate = storage_mut.scope.isolate;
1001    if storage_mut.scope.needs_scope {
1002      unsafe {
1003        raw::HandleScope::init(
1004          &mut storage_mut.scope.raw_handle_scope,
1005          isolate,
1006        );
1007      }
1008    }
1009
1010    let projected = &mut storage_mut.scope;
1011    unsafe { Pin::new_unchecked(projected) }
1012  }
1013
1014  unsafe fn deinit(me: &mut Self) {
1015    if me.needs_scope {
1016      unsafe { raw::v8__HandleScope__DESTRUCT(&mut me.raw_handle_scope) };
1017    }
1018  }
1019}
1020
1021impl<C> sealed::Sealed for CallbackScope<'_, C> {}
1022impl<C> Scope for CallbackScope<'_, C> {}
1023
1024pub trait NewCallbackScope<'s>: Sized + GetIsolate {
1025  type NewScope: Scope;
1026  const NEEDS_SCOPE: bool = false;
1027
1028  #[inline]
1029  fn get_context(&self) -> Option<Local<'s, Context>> {
1030    None
1031  }
1032
1033  fn make_new_scope(me: Self) -> Self::NewScope;
1034}
1035
1036fn make_new_callback_scope<'a, C>(
1037  isolate: impl GetIsolate,
1038  context: Option<NonNull<Context>>,
1039) -> CallbackScope<'a, C> {
1040  CallbackScope {
1041    raw_handle_scope: unsafe { raw::HandleScope::uninit() },
1042    isolate: unsafe { NonNull::new_unchecked(isolate.get_isolate_ptr()) },
1043    context: Cell::new(context),
1044    _phantom: PhantomData,
1045    _pinned: PhantomPinned,
1046    needs_scope: false,
1047  }
1048}
1049
1050impl<'s> NewCallbackScope<'s> for &'s mut Isolate {
1051  type NewScope = CallbackScope<'s, ()>;
1052
1053  fn make_new_scope(me: Self) -> Self::NewScope {
1054    make_new_callback_scope(&*me, None)
1055  }
1056}
1057
1058impl<'s> NewCallbackScope<'s> for &'s mut OwnedIsolate {
1059  type NewScope = CallbackScope<'s, ()>;
1060
1061  fn make_new_scope(me: Self) -> Self::NewScope {
1062    make_new_callback_scope(&*me, None)
1063  }
1064}
1065
1066impl<'s> NewCallbackScope<'s> for &'s FunctionCallbackInfo {
1067  type NewScope = CallbackScope<'s>;
1068
1069  fn make_new_scope(me: Self) -> Self::NewScope {
1070    make_new_callback_scope(me, None)
1071  }
1072}
1073
1074impl<'s, T> NewCallbackScope<'s> for &'s PropertyCallbackInfo<T> {
1075  type NewScope = CallbackScope<'s>;
1076
1077  fn make_new_scope(me: Self) -> Self::NewScope {
1078    make_new_callback_scope(me, None)
1079  }
1080}
1081
1082impl<'s> NewCallbackScope<'s> for &'s FastApiCallbackOptions<'s> {
1083  type NewScope = CallbackScope<'s>;
1084  const NEEDS_SCOPE: bool = true;
1085
1086  fn make_new_scope(me: Self) -> Self::NewScope {
1087    let isolate = (*me).get_isolate_ptr();
1088    CallbackScope {
1089      raw_handle_scope: unsafe { raw::HandleScope::uninit() },
1090      isolate: unsafe { NonNull::new_unchecked(isolate) },
1091      context: Cell::new(me.get_context().map(|c| c.as_non_null())),
1092      _phantom: PhantomData,
1093      _pinned: PhantomPinned,
1094      needs_scope: Self::NEEDS_SCOPE,
1095    }
1096  }
1097}
1098
1099impl<'s> NewCallbackScope<'s> for Local<'s, Context> {
1100  type NewScope = CallbackScope<'s>;
1101
1102  #[inline]
1103  fn get_context(&self) -> Option<Local<'s, Context>> {
1104    Some(*self)
1105  }
1106
1107  fn make_new_scope(me: Self) -> Self::NewScope {
1108    make_new_callback_scope(me, Some(me.as_non_null()))
1109  }
1110}
1111
1112impl<'s> NewCallbackScope<'s> for Local<'s, Message> {
1113  type NewScope = CallbackScope<'s>;
1114
1115  fn make_new_scope(me: Self) -> Self::NewScope {
1116    make_new_callback_scope(me, None)
1117  }
1118}
1119
1120impl<'s, T: Into<Local<'s, Object>> + GetIsolate> NewCallbackScope<'s> for T {
1121  type NewScope = CallbackScope<'s>;
1122
1123  fn make_new_scope(me: Self) -> Self::NewScope {
1124    make_new_callback_scope(me, None)
1125  }
1126}
1127
1128impl<'s> NewCallbackScope<'s> for &'s PromiseRejectMessage<'s> {
1129  type NewScope = CallbackScope<'s>;
1130
1131  fn make_new_scope(me: Self) -> Self::NewScope {
1132    make_new_callback_scope(me, None)
1133  }
1134}
1135
1136impl<'s> AsRef<Pin<&'s mut HandleScope<'s, ()>>> for CallbackScope<'s, ()> {
1137  fn as_ref(&self) -> &Pin<&'s mut HandleScope<'s, ()>> {
1138    unsafe { std::mem::transmute(self) }
1139  }
1140}
1141
1142/// An external exception handler.
1143#[repr(C)]
1144pub struct TryCatch<'scope, 'obj, P> {
1145  raw_try_catch: raw::TryCatch,
1146  scope: &'scope mut PinnedRef<'obj, P>,
1147  _pinned: PhantomPinned,
1148}
1149
1150impl<'scope, P: NewTryCatch<'scope>> TryCatch<'scope, '_, P> {
1151  #[allow(clippy::new_ret_no_self)]
1152  pub fn new(param: &'scope mut P) -> ScopeStorage<P::NewScope> {
1153    ScopeStorage::new(P::make_new_scope(param))
1154  }
1155}
1156
1157impl<P: GetIsolate> ScopeInit for TryCatch<'_, '_, P> {
1158  fn init_stack(storage: Pin<&mut ScopeStorage<Self>>) -> Pin<&mut Self> {
1159    let storage_mut = unsafe { storage.get_unchecked_mut() };
1160    let isolate = unsafe {
1161      NonNull::new_unchecked(storage_mut.scope.scope.get_isolate_ptr())
1162    };
1163    unsafe {
1164      raw::TryCatch::init(&mut storage_mut.scope.raw_try_catch, isolate);
1165    }
1166    let projected = &mut storage_mut.scope;
1167    unsafe { Pin::new_unchecked(projected) }
1168  }
1169
1170  unsafe fn deinit(me: &mut Self) {
1171    unsafe { raw::v8__TryCatch__DESTRUCT(&mut me.raw_try_catch) };
1172  }
1173}
1174
1175impl<'scope, 'obj: 'scope, 'iso: 'obj, P: GetIsolate>
1176  PinnedRef<'_, TryCatch<'scope, 'obj, P>>
1177where
1178  PinnedRef<'obj, P>: AsRef<PinnedRef<'obj, HandleScope<'iso>>>,
1179{
1180  /// Returns true if an exception has been caught by this try/catch block.
1181  #[inline(always)]
1182  pub fn has_caught(&self) -> bool {
1183    unsafe { raw::v8__TryCatch__HasCaught(self.get_raw()) }
1184  }
1185
1186  /// For certain types of exceptions, it makes no sense to continue execution.
1187  ///
1188  /// If CanContinue returns false, the correct action is to perform any C++
1189  /// cleanup needed and then return. If CanContinue returns false and
1190  /// HasTerminated returns true, it is possible to call
1191  /// CancelTerminateExecution in order to continue calling into the engine.
1192  #[inline(always)]
1193  pub fn can_continue(&self) -> bool {
1194    unsafe { raw::v8__TryCatch__CanContinue(self.get_raw()) }
1195  }
1196
1197  /// Returns true if an exception has been caught due to script execution
1198  /// being terminated.
1199  ///
1200  /// There is no JavaScript representation of an execution termination
1201  /// exception. Such exceptions are thrown when the TerminateExecution
1202  /// methods are called to terminate a long-running script.
1203  ///
1204  /// If such an exception has been thrown, HasTerminated will return true,
1205  /// indicating that it is possible to call CancelTerminateExecution in order
1206  /// to continue calling into the engine.
1207  #[inline(always)]
1208  pub fn has_terminated(&self) -> bool {
1209    unsafe { raw::v8__TryCatch__HasTerminated(self.get_raw()) }
1210  }
1211
1212  /// Returns true if verbosity is enabled.
1213  #[inline(always)]
1214  pub fn is_verbose(&self) -> bool {
1215    unsafe { raw::v8__TryCatch__IsVerbose(self.get_raw()) }
1216  }
1217
1218  /// Set verbosity of the external exception handler.
1219  ///
1220  /// By default, exceptions that are caught by an external exception
1221  /// handler are not reported. Call SetVerbose with true on an
1222  /// external exception handler to have exceptions caught by the
1223  /// handler reported as if they were not caught.
1224  #[inline(always)]
1225  pub fn set_verbose(&mut self, value: bool) {
1226    unsafe { raw::v8__TryCatch__SetVerbose(self.get_raw_mut(), value) };
1227  }
1228
1229  /// Set whether or not this TryCatch should capture a Message object
1230  /// which holds source information about where the exception
1231  /// occurred. True by default.
1232  #[inline(always)]
1233  pub fn set_capture_message(&mut self, value: bool) {
1234    unsafe { raw::v8__TryCatch__SetCaptureMessage(self.get_raw_mut(), value) };
1235  }
1236
1237  /// Clears any exceptions that may have been caught by this try/catch block.
1238  /// After this method has been called, HasCaught() will return false. Cancels
1239  /// the scheduled exception if it is caught and ReThrow() is not called
1240  /// before.
1241  ///
1242  /// It is not necessary to clear a try/catch block before using it again; if
1243  /// another exception is thrown the previously caught exception will just be
1244  /// overwritten. However, it is often a good idea since it makes it easier
1245  /// to determine which operation threw a given exception.
1246  #[inline(always)]
1247  pub fn reset(&mut self) {
1248    unsafe { raw::v8__TryCatch__Reset(self.get_raw_mut()) };
1249  }
1250
1251  #[inline(always)]
1252  fn get_raw(&self) -> &raw::TryCatch {
1253    &self.0.raw_try_catch
1254  }
1255
1256  #[inline(always)]
1257  unsafe fn get_raw_mut(&mut self) -> &mut raw::TryCatch {
1258    unsafe { &mut self.0.as_mut().get_unchecked_mut().raw_try_catch }
1259  }
1260
1261  pub fn exception(&self) -> Option<Local<'obj, Value>> {
1262    unsafe {
1263      self
1264        .0
1265        .scope
1266        .as_ref()
1267        .cast_local(|_data| raw::v8__TryCatch__Exception(self.get_raw()))
1268    }
1269  }
1270
1271  pub fn message(&self) -> Option<Local<'obj, Message>> {
1272    unsafe {
1273      self
1274        .0
1275        .scope
1276        .as_ref()
1277        .cast_local(|_data| raw::v8__TryCatch__Message(self.get_raw()))
1278    }
1279  }
1280
1281  pub fn rethrow(&mut self) -> Option<Local<'obj, Value>> {
1282    let raw_mut = unsafe { self.get_raw_mut() as *mut raw::TryCatch };
1283    unsafe {
1284      self
1285        .0
1286        .scope
1287        .as_ref()
1288        .cast_local(|_data| raw::v8__TryCatch__ReThrow(raw_mut))
1289    }
1290  }
1291
1292  pub fn stack_trace(&self) -> Option<Local<'obj, Value>> {
1293    unsafe {
1294      self.0.scope.as_ref().cast_local(|_data| {
1295        raw::v8__TryCatch__StackTrace(
1296          self.get_raw(),
1297          _data.get_current_context(),
1298        )
1299      })
1300    }
1301  }
1302}
1303
1304impl<P> sealed::Sealed for TryCatch<'_, '_, P> {}
1305impl<P: Scope + GetIsolate> Scope for TryCatch<'_, '_, P> {}
1306
1307pub trait NewTryCatch<'scope>: GetIsolate {
1308  type NewScope: Scope;
1309  fn make_new_scope(me: &'scope mut Self) -> Self::NewScope;
1310}
1311
1312impl<'scope, 'obj: 'scope, 'i, C> NewTryCatch<'scope>
1313  for PinnedRef<'obj, HandleScope<'i, C>>
1314{
1315  type NewScope = TryCatch<'scope, 'obj, HandleScope<'i, C>>;
1316  fn make_new_scope(me: &'scope mut Self) -> Self::NewScope {
1317    TryCatch {
1318      scope: me,
1319      raw_try_catch: unsafe { raw::TryCatch::uninit() },
1320      _pinned: PhantomPinned,
1321    }
1322  }
1323}
1324
1325// the lifetimes here are:
1326// - 'borrow: the lifetime of the borrow of the scope
1327// - 'scope: the lifetime of the escapable handle scope
1328// - 'obj: the lifetime of the handles created from the escapable handle scope
1329// - 'esc: the lifetime of the slot that the escapable handle scope will eventually escape to. this must be longer than 'obj
1330impl<'borrow, 'scope: 'borrow, 'obj: 'borrow, 'esc: 'obj, C>
1331  NewTryCatch<'borrow>
1332  for PinnedRef<'scope, EscapableHandleScope<'obj, 'esc, C>>
1333{
1334  type NewScope =
1335    TryCatch<'borrow, 'scope, EscapableHandleScope<'obj, 'esc, C>>;
1336
1337  fn make_new_scope(me: &'borrow mut Self) -> Self::NewScope {
1338    TryCatch {
1339      scope: me,
1340      raw_try_catch: unsafe { raw::TryCatch::uninit() },
1341      _pinned: PhantomPinned,
1342    }
1343  }
1344}
1345
1346impl<'scope, 'obj: 'scope, T: GetIsolate + Scope + ClearCachedContext>
1347  NewTryCatch<'scope> for ContextScope<'_, 'obj, T>
1348{
1349  type NewScope = TryCatch<'scope, 'obj, T>;
1350  fn make_new_scope(me: &'scope mut Self) -> Self::NewScope {
1351    TryCatch {
1352      scope: me,
1353      raw_try_catch: unsafe { raw::TryCatch::uninit() },
1354      _pinned: PhantomPinned,
1355    }
1356  }
1357}
1358
1359impl<'scope, 'obj: 'scope, 'i, C> NewTryCatch<'scope>
1360  for PinnedRef<'obj, CallbackScope<'i, C>>
1361{
1362  type NewScope = TryCatch<'scope, 'i, HandleScope<'i, C>>;
1363  fn make_new_scope(me: &'scope mut Self) -> Self::NewScope {
1364    TryCatch {
1365      scope: unsafe {
1366        std::mem::transmute::<
1367          &mut PinnedRef<'_, CallbackScope<'_, C>>,
1368          &mut PinnedRef<'_, HandleScope<'_, C>>,
1369        >(me)
1370      },
1371      raw_try_catch: unsafe { raw::TryCatch::uninit() },
1372      _pinned: PhantomPinned,
1373    }
1374  }
1375}
1376
1377impl<'scope, 'obj: 'scope, 'obj_outer: 'obj, 'iso, C> NewTryCatch<'scope>
1378  for PinnedRef<'obj, TryCatch<'_, 'obj_outer, HandleScope<'iso, C>>>
1379{
1380  type NewScope = TryCatch<'scope, 'obj_outer, HandleScope<'iso, C>>;
1381  fn make_new_scope(me: &'scope mut Self) -> Self::NewScope {
1382    TryCatch {
1383      scope: unsafe { me.as_mut_ref().0.get_unchecked_mut().scope },
1384      raw_try_catch: unsafe { raw::TryCatch::uninit() },
1385      _pinned: PhantomPinned,
1386    }
1387  }
1388}
1389
1390/// A HandleScope which first allocates a handle in the current scope
1391/// which will be later filled with the escape value.
1392#[repr(C)]
1393pub struct EscapableHandleScope<'s, 'esc: 's, C = Context> {
1394  raw_handle_scope: raw::HandleScope,
1395  isolate: NonNull<RealIsolate>,
1396  context: Cell<Option<NonNull<Context>>>,
1397  _phantom:
1398    PhantomData<(&'s mut raw::HandleScope, &'esc mut raw::EscapeSlot, &'s C)>,
1399  _pinned: PhantomPinned,
1400  raw_escape_slot: Option<raw::EscapeSlot>,
1401}
1402
1403assert_layout_subset!(HandleScope<'static, ()>, EscapableHandleScope<'static, 'static, ()> {
1404  raw_handle_scope,
1405  isolate,
1406  context,
1407  _phantom,
1408  _pinned,
1409});
1410
1411impl<'s, 'esc: 's, C> ScopeInit for EscapableHandleScope<'s, 'esc, C> {
1412  fn init_stack(storage: Pin<&mut ScopeStorage<Self>>) -> Pin<&mut Self> {
1413    let storage_mut = unsafe { storage.get_unchecked_mut() };
1414    unsafe {
1415      let isolate = storage_mut.scope.isolate;
1416      raw::HandleScope::init(&mut storage_mut.scope.raw_handle_scope, isolate);
1417    }
1418    let projected = &mut storage_mut.scope;
1419
1420    unsafe { Pin::new_unchecked(projected) }
1421  }
1422
1423  unsafe fn deinit(me: &mut Self) {
1424    unsafe { raw::v8__HandleScope__DESTRUCT(&raw mut me.raw_handle_scope) };
1425  }
1426}
1427
1428impl<'s, 'esc: 's> EscapableHandleScope<'s, 'esc> {
1429  #[allow(clippy::new_ret_no_self)]
1430  pub fn new<P: NewEscapableHandleScope<'s>>(
1431    scope: &'s mut P,
1432  ) -> ScopeStorage<P::NewScope> {
1433    ScopeStorage::new(P::make_new_scope(scope))
1434  }
1435}
1436
1437impl<'s, 'esc: 's, C> PinnedRef<'_, EscapableHandleScope<'s, 'esc, C>> {
1438  /// Pushes the value into the previous scope and returns a handle to it.
1439  /// Cannot be called twice.
1440  pub fn escape<'a, T>(&mut self, value: Local<'a, T>) -> Local<'esc, T>
1441  where
1442    for<'l> Local<'l, T>: Into<Local<'l, crate::Data>>,
1443  {
1444    let escape_slot = unsafe { self.0.as_mut().get_unchecked_mut() }
1445      .raw_escape_slot
1446      .take()
1447      .expect("EscapableHandleScope::escape() called twice");
1448    escape_slot.escape(value)
1449  }
1450}
1451
1452impl<'p, 's, 'esc: 's, C> Deref
1453  for PinnedRef<'p, EscapableHandleScope<'s, 'esc, C>>
1454{
1455  type Target = PinnedRef<'p, HandleScope<'s, C>>;
1456  fn deref(&self) -> &Self::Target {
1457    unsafe { std::mem::transmute(self) }
1458  }
1459}
1460
1461impl<'s, 'esc: 's, C> DerefMut
1462  for PinnedRef<'_, EscapableHandleScope<'s, 'esc, C>>
1463{
1464  fn deref_mut(&mut self) -> &mut Self::Target {
1465    unsafe { std::mem::transmute(self) }
1466  }
1467}
1468
1469pub trait NewEscapableHandleScope<'s> {
1470  type NewScope: Scope;
1471  fn make_new_scope(me: &'s mut Self) -> Self::NewScope;
1472}
1473
1474impl<'s, 'obj: 's, C> NewEscapableHandleScope<'s>
1475  for PinnedRef<'obj, HandleScope<'_, C>>
1476{
1477  type NewScope = EscapableHandleScope<'s, 'obj, C>;
1478  fn make_new_scope(me: &'s mut Self) -> Self::NewScope {
1479    // Note: the `raw_escape_slot` field must be initialized _before_ the
1480    // `raw_handle_scope` field, otherwise the escaped local handle ends up
1481    // inside the `EscapableHandleScope` that's being constructed here,
1482    // rather than escaping from it.
1483    let isolate = me.0.isolate;
1484    let raw_escape_slot = raw::EscapeSlot::new(isolate);
1485    let raw_handle_scope = unsafe { raw::HandleScope::uninit() };
1486
1487    EscapableHandleScope {
1488      isolate,
1489      context: Cell::new(me.0.context.get()),
1490      raw_escape_slot: Some(raw_escape_slot),
1491      raw_handle_scope,
1492      _phantom: PhantomData,
1493      _pinned: PhantomPinned,
1494    }
1495  }
1496}
1497
1498impl<'borrow, 'obj: 'borrow, C> NewEscapableHandleScope<'borrow>
1499  for ContextScope<'_, 'obj, HandleScope<'_, C>>
1500{
1501  type NewScope = EscapableHandleScope<'borrow, 'obj, C>;
1502  fn make_new_scope(me: &'borrow mut Self) -> Self::NewScope {
1503    NewEscapableHandleScope::make_new_scope(me.scope)
1504  }
1505}
1506
1507impl<'borrow, 's: 'borrow, 'esc: 'borrow, C> NewEscapableHandleScope<'borrow>
1508  for PinnedRef<'_, EscapableHandleScope<'s, 'esc, C>>
1509{
1510  type NewScope = EscapableHandleScope<'borrow, 's, C>;
1511  fn make_new_scope(me: &'borrow mut Self) -> Self::NewScope {
1512    // Note: the `raw_escape_slot` field must be initialized _before_ the
1513    // `raw_handle_scope` field, otherwise the escaped local handle ends up
1514    // inside the `EscapableHandleScope` that's being constructed here,
1515    // rather than escaping from it.
1516    let isolate = me.0.isolate;
1517    let raw_escape_slot = raw::EscapeSlot::new(isolate);
1518    let raw_handle_scope = unsafe { raw::HandleScope::uninit() };
1519    EscapableHandleScope {
1520      isolate,
1521      context: Cell::new(me.0.context.get()),
1522      raw_escape_slot: Some(raw_escape_slot),
1523      raw_handle_scope,
1524      _phantom: PhantomData,
1525      _pinned: PhantomPinned,
1526    }
1527  }
1528}
1529
1530impl<'s, 'esc: 's, C> sealed::Sealed for EscapableHandleScope<'s, 'esc, C> {}
1531impl<'s, 'esc: 's, C> Scope for EscapableHandleScope<'s, 'esc, C> {}
1532
1533#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1534#[repr(C)]
1535pub enum OnFailure {
1536  CrashOnFailure,
1537  ThrowOnFailure,
1538  DumpOnFailure,
1539}
1540
1541#[repr(C)]
1542pub struct DisallowJavascriptExecutionScope<'scope, 'obj, P> {
1543  raw: raw::DisallowJavascriptExecutionScope,
1544  scope: &'scope mut PinnedRef<'obj, P>,
1545  on_failure: OnFailure,
1546  _pinned: PhantomPinned,
1547}
1548
1549impl<P: GetIsolate> ScopeInit for DisallowJavascriptExecutionScope<'_, '_, P> {
1550  fn init_stack(storage: Pin<&mut ScopeStorage<Self>>) -> Pin<&mut Self> {
1551    // SAFETY: we aren't going to move the raw scope out
1552    let storage_mut = unsafe { storage.get_unchecked_mut() };
1553    let isolate = storage_mut.scope.scope.get_isolate_ptr();
1554    let on_failure = storage_mut.scope.on_failure;
1555    // SAFETY: calling the raw function, isolate is valid, and the raw scope won't be moved
1556    unsafe {
1557      raw::DisallowJavascriptExecutionScope::init(
1558        &mut storage_mut.scope.raw,
1559        NonNull::new_unchecked(isolate),
1560        on_failure,
1561      );
1562      Pin::new_unchecked(&mut storage_mut.scope)
1563    }
1564  }
1565
1566  unsafe fn deinit(me: &mut Self) {
1567    unsafe { raw::v8__DisallowJavascriptExecutionScope__DESTRUCT(&mut me.raw) };
1568  }
1569}
1570
1571impl<P: GetIsolate> sealed::Sealed
1572  for DisallowJavascriptExecutionScope<'_, '_, P>
1573{
1574}
1575impl<P: Scope + GetIsolate> Scope
1576  for DisallowJavascriptExecutionScope<'_, '_, P>
1577{
1578}
1579
1580impl<'scope, P: NewDisallowJavascriptExecutionScope<'scope>>
1581  DisallowJavascriptExecutionScope<'scope, '_, P>
1582{
1583  #[allow(clippy::new_ret_no_self)]
1584  pub fn new(
1585    param: &'scope mut P,
1586    on_failure: OnFailure,
1587  ) -> ScopeStorage<P::NewScope> {
1588    ScopeStorage::new(P::make_new_scope(param, on_failure))
1589  }
1590}
1591
1592pub trait NewDisallowJavascriptExecutionScope<'scope> {
1593  type NewScope: Scope;
1594  fn make_new_scope(
1595    me: &'scope mut Self,
1596    on_failure: OnFailure,
1597  ) -> Self::NewScope;
1598}
1599
1600impl<'scope, 'obj, P> NewDisallowJavascriptExecutionScope<'scope>
1601  for ContextScope<'_, 'obj, P>
1602where
1603  P: ClearCachedContext,
1604  PinnedRef<'obj, P>: NewDisallowJavascriptExecutionScope<'scope>,
1605{
1606  type NewScope = <PinnedRef<'obj, P> as NewDisallowJavascriptExecutionScope<
1607    'scope,
1608  >>::NewScope;
1609  fn make_new_scope(
1610    me: &'scope mut Self,
1611    on_failure: OnFailure,
1612  ) -> Self::NewScope {
1613    PinnedRef::<'obj, P>::make_new_scope(me.scope, on_failure)
1614  }
1615}
1616
1617impl<'scope, 'obj: 'scope, P: Scope + GetIsolate>
1618  NewDisallowJavascriptExecutionScope<'scope> for PinnedRef<'obj, P>
1619{
1620  type NewScope = DisallowJavascriptExecutionScope<'scope, 'obj, P>;
1621
1622  fn make_new_scope(
1623    me: &'scope mut Self,
1624    on_failure: OnFailure,
1625  ) -> Self::NewScope {
1626    DisallowJavascriptExecutionScope {
1627      raw: unsafe { raw::DisallowJavascriptExecutionScope::uninit() },
1628      scope: me,
1629      on_failure,
1630      _pinned: PhantomPinned,
1631    }
1632  }
1633}
1634
1635#[repr(C)]
1636pub struct AllowJavascriptExecutionScope<'scope, 'obj, P> {
1637  raw: raw::AllowJavascriptExecutionScope,
1638  scope: &'scope mut PinnedRef<'obj, P>,
1639  _pinned: PhantomPinned,
1640}
1641
1642impl<P: GetIsolate> ScopeInit for AllowJavascriptExecutionScope<'_, '_, P> {
1643  fn init_stack(storage: Pin<&mut ScopeStorage<Self>>) -> Pin<&mut Self> {
1644    let storage_mut = unsafe { storage.get_unchecked_mut() };
1645    let isolate = unsafe {
1646      NonNull::new_unchecked(storage_mut.scope.scope.get_isolate_ptr())
1647    };
1648    unsafe {
1649      raw::AllowJavascriptExecutionScope::init(
1650        &mut storage_mut.scope.raw,
1651        isolate,
1652      );
1653    }
1654    let projected = &mut storage_mut.scope;
1655    unsafe { Pin::new_unchecked(projected) }
1656  }
1657
1658  unsafe fn deinit(me: &mut Self) {
1659    unsafe { raw::v8__AllowJavascriptExecutionScope__DESTRUCT(&mut me.raw) };
1660  }
1661}
1662
1663impl<P: GetIsolate> sealed::Sealed
1664  for AllowJavascriptExecutionScope<'_, '_, P>
1665{
1666}
1667impl<P: Scope + GetIsolate> Scope for AllowJavascriptExecutionScope<'_, '_, P> {}
1668
1669impl<'scope, P: NewAllowJavascriptExecutionScope<'scope>>
1670  AllowJavascriptExecutionScope<'scope, '_, P>
1671{
1672  #[allow(clippy::new_ret_no_self)]
1673  pub fn new(param: &'scope mut P) -> ScopeStorage<P::NewScope> {
1674    ScopeStorage::new(P::make_new_scope(param))
1675  }
1676}
1677
1678pub trait NewAllowJavascriptExecutionScope<'scope> {
1679  type NewScope: Scope;
1680  fn make_new_scope(me: &'scope mut Self) -> Self::NewScope;
1681}
1682
1683impl<'scope, 'obj: 'scope, P: Scope + GetIsolate>
1684  NewAllowJavascriptExecutionScope<'scope> for PinnedRef<'obj, P>
1685{
1686  type NewScope = AllowJavascriptExecutionScope<'scope, 'obj, P>;
1687  fn make_new_scope(me: &'scope mut Self) -> Self::NewScope {
1688    AllowJavascriptExecutionScope {
1689      raw: unsafe { raw::AllowJavascriptExecutionScope::uninit() },
1690      scope: me,
1691      _pinned: PhantomPinned,
1692    }
1693  }
1694}
1695
1696// Note: the macros below _do not_ use std::pin::pin! because
1697// it leads to worse compiler errors when the scope doesn't live long enough.
1698// Instead, we do the same thing as std::pin::pin! but without the additional temporary scope.
1699
1700#[allow(unused_macros, clippy::macro_metavars_in_unsafe)]
1701#[macro_export]
1702macro_rules! callback_scope {
1703  (unsafe $scope: ident, $param: expr $(,)?) => {
1704    #[allow(clippy::macro_metavars_in_unsafe)]
1705    let mut $scope = {
1706      // force the caller to put a separate unsafe block around the param expr
1707      let param = $param;
1708      unsafe { $crate::CallbackScope::new(param) }
1709    };
1710    // SAFETY: we are shadowing the original binding, so it can't be accessed
1711    // ever again
1712    let mut $scope = {
1713      let scope_pinned = unsafe { std::pin::Pin::new_unchecked(&mut $scope) };
1714      scope_pinned.init()
1715    };
1716    let $scope = &mut $scope;
1717  };
1718  (unsafe let $scope: ident, $param: expr $(,)?) => {
1719    $crate::callback_scope!(unsafe $scope, $param);
1720  }
1721}
1722
1723#[allow(unused_imports)]
1724pub(crate) use callback_scope;
1725
1726/// Creates a pinned `HandleScope` and binds `&mut PinScope` to `$scope`.
1727///
1728/// ```rust
1729/// v8::scope!(let scope, isolate);
1730/// ```
1731#[allow(unused_macros)]
1732#[macro_export]
1733macro_rules! scope {
1734  ($scope: ident, $param: expr $(,)?) => {
1735    let mut $scope = $crate::HandleScope::new($param);
1736    // SAFETY: we are shadowing the original binding, so it can't be accessed
1737    // ever again
1738    let mut $scope = {
1739      let scope_pinned = unsafe { std::pin::Pin::new_unchecked(&mut $scope) };
1740      scope_pinned.init()
1741    };
1742    let $scope = &mut $scope;
1743  };
1744  (let $scope: ident, $param: expr $(,)?) => {
1745    $crate::scope!($scope, $param);
1746  };
1747}
1748
1749#[allow(unused_imports)]
1750pub(crate) use scope;
1751
1752#[allow(unused_macros)]
1753#[macro_export]
1754macro_rules! scope_with_context {
1755  ($scope: ident, $param: expr, $context: expr $(,)?) => {
1756    let mut $scope = $crate::HandleScope::new($param);
1757    // SAFETY: we are shadowing the original binding, so it can't be accessed
1758    // ever again
1759    let mut $scope = {
1760      let scope_pinned = unsafe { std::pin::Pin::new_unchecked(&mut $scope) };
1761      scope_pinned.init()
1762    };
1763    let $scope = &mut $scope;
1764    let context = v8::Local::new($scope, $context);
1765    let $scope = &mut $crate::ContextScope::new($scope, context);
1766  };
1767  (let $scope: ident, $param: expr, $context: expr $(,)?) => {
1768    $crate::scope_with_context!($scope, $param, $context);
1769  };
1770}
1771
1772#[allow(unused_imports)]
1773pub(crate) use scope_with_context;
1774
1775#[allow(unused_macros)]
1776#[macro_export]
1777macro_rules! tc_scope {
1778  ($scope: ident, $param: expr $(,)?) => {
1779    let mut $scope = $crate::TryCatch::new($param);
1780    // SAFETY: we are shadowing the original binding, so it can't be accessed
1781    // ever again
1782    let mut $scope = {
1783      let scope_pinned = unsafe { std::pin::Pin::new_unchecked(&mut $scope) };
1784      scope_pinned.init()
1785    };
1786    let $scope = &mut $scope;
1787  };
1788  (let $scope: ident, $param: expr $(,)?) => {
1789    $crate::tc_scope!($scope, $param);
1790  };
1791}
1792
1793#[macro_export]
1794macro_rules! disallow_javascript_execution_scope {
1795  ($scope: ident, $param: expr, $on_failure: expr $(,)?) => {
1796    let mut $scope =
1797      $crate::DisallowJavascriptExecutionScope::new($param, $on_failure);
1798    // SAFETY: we are shadowing the original binding, so it can't be accessed
1799    // ever again
1800    let mut $scope = {
1801      let scope_pinned = unsafe { std::pin::Pin::new_unchecked(&mut $scope) };
1802      scope_pinned.init()
1803    };
1804    let $scope = &mut $scope;
1805  };
1806  (let $scope: ident, $param: expr, $on_failure: expr $(,)?) => {
1807    $crate::disallow_javascript_execution_scope!($scope, $param, $on_failure);
1808  };
1809}
1810
1811#[allow(unused_imports)]
1812pub(crate) use disallow_javascript_execution_scope;
1813
1814#[macro_export]
1815macro_rules! allow_javascript_execution_scope {
1816  ($scope: ident, $param: expr $(,)?) => {
1817    let mut $scope = $crate::AllowJavascriptExecutionScope::new($param);
1818    let mut $scope = {
1819      let scope_pinned = unsafe { std::pin::Pin::new_unchecked(&mut $scope) };
1820      scope_pinned.init()
1821    };
1822    let $scope = &mut $scope;
1823  };
1824  (let $scope: ident, $param: expr $(,)?) => {
1825    $crate::allow_javascript_execution_scope!($scope, $param);
1826  };
1827}
1828
1829#[allow(unused_imports)]
1830pub(crate) use allow_javascript_execution_scope;
1831
1832#[macro_export]
1833macro_rules! escapable_handle_scope {
1834  ($scope: ident, $param: expr $(,)?) => {
1835    let mut $scope = $crate::EscapableHandleScope::new($param);
1836    let mut $scope = {
1837      let scope_pinned = unsafe { std::pin::Pin::new_unchecked(&mut $scope) };
1838      scope_pinned.init()
1839    };
1840    let $scope = &mut $scope;
1841  };
1842  (let $scope: ident, $param: expr $(,)?) => {
1843    $crate::escapable_handle_scope!($scope, $param);
1844  };
1845}
1846
1847#[allow(unused_imports)]
1848pub(crate) use escapable_handle_scope;
1849
1850#[repr(transparent)]
1851pub struct PinnedRef<'p, T>(Pin<&'p mut T>);
1852
1853impl<'p, T> From<Pin<&'p mut T>> for PinnedRef<'p, T> {
1854  fn from(value: Pin<&'p mut T>) -> Self {
1855    PinnedRef(value)
1856  }
1857}
1858
1859impl<T> PinnedRef<'_, T> {
1860  pub fn as_mut_ref(&mut self) -> PinnedRef<'_, T> {
1861    PinnedRef(self.0.as_mut())
1862  }
1863}
1864
1865unsafe fn cast_pinned_ref<'b, 'o, I, O>(
1866  pinned: &PinnedRef<'_, I>,
1867) -> &'b PinnedRef<'o, O> {
1868  unsafe { std::mem::transmute(pinned) }
1869}
1870
1871unsafe fn cast_pinned_ref_mut<'b, 'o, I, O>(
1872  pinned: &mut PinnedRef<'_, I>,
1873) -> &'b mut PinnedRef<'o, O> {
1874  unsafe { std::mem::transmute(pinned) }
1875}
1876
1877impl<'p, 'i> Deref for PinnedRef<'p, HandleScope<'i>> {
1878  type Target = PinnedRef<'p, HandleScope<'i, ()>>;
1879  fn deref(&self) -> &Self::Target {
1880    unsafe { cast_pinned_ref::<HandleScope<'i>, HandleScope<'i, ()>>(self) }
1881  }
1882}
1883
1884impl DerefMut for PinnedRef<'_, HandleScope<'_>> {
1885  fn deref_mut(&mut self) -> &mut Self::Target {
1886    unsafe { cast_pinned_ref_mut::<HandleScope<'_>, HandleScope<'_, ()>>(self) }
1887  }
1888}
1889
1890impl Deref for PinnedRef<'_, HandleScope<'_, ()>> {
1891  type Target = Isolate;
1892  #[inline(always)]
1893  fn deref(&self) -> &Self::Target {
1894    unsafe { Isolate::from_raw_ref(&self.0.isolate) }
1895  }
1896}
1897
1898impl DerefMut for PinnedRef<'_, HandleScope<'_, ()>> {
1899  fn deref_mut(&mut self) -> &mut Self::Target {
1900    unsafe {
1901      Isolate::from_raw_ref_mut(
1902        &mut self.0.as_mut().get_unchecked_mut().isolate,
1903      )
1904    }
1905  }
1906}
1907
1908impl<'i> Deref for PinnedRef<'_, CallbackScope<'i>> {
1909  // You may notice the output lifetime is a little bit weird here.
1910  // Basically, we're saying that any Handles created from this `CallbackScope`
1911  // will live as long as the thing that we made the `CallbackScope` from.
1912  // In practice, this means that the caller of `CallbackScope::new` needs to
1913  // be careful to ensure that the input lifetime is a safe approximation.
1914  type Target = PinnedRef<'i, HandleScope<'i>>;
1915  fn deref(&self) -> &Self::Target {
1916    unsafe { cast_pinned_ref::<CallbackScope<'i>, HandleScope<'i>>(self) }
1917  }
1918}
1919
1920impl DerefMut for PinnedRef<'_, CallbackScope<'_>> {
1921  fn deref_mut(&mut self) -> &mut Self::Target {
1922    unsafe { cast_pinned_ref_mut::<CallbackScope<'_>, HandleScope<'_>>(self) }
1923  }
1924}
1925
1926impl<'i> Deref for PinnedRef<'_, CallbackScope<'i, ()>> {
1927  type Target = PinnedRef<'i, HandleScope<'i, ()>>;
1928  fn deref(&self) -> &Self::Target {
1929    unsafe {
1930      cast_pinned_ref::<CallbackScope<'i, ()>, HandleScope<'i, ()>>(self)
1931    }
1932  }
1933}
1934
1935impl DerefMut for PinnedRef<'_, CallbackScope<'_, ()>> {
1936  fn deref_mut(&mut self) -> &mut Self::Target {
1937    unsafe {
1938      cast_pinned_ref_mut::<CallbackScope<'_, ()>, HandleScope<'_, ()>>(self)
1939    }
1940  }
1941}
1942
1943impl<'obj, 'iso, C> Deref
1944  for PinnedRef<'_, TryCatch<'_, 'obj, HandleScope<'iso, C>>>
1945{
1946  type Target = PinnedRef<'obj, HandleScope<'iso, C>>;
1947  fn deref(&self) -> &Self::Target {
1948    self.0.scope
1949  }
1950}
1951
1952impl<C> DerefMut for PinnedRef<'_, TryCatch<'_, '_, HandleScope<'_, C>>> {
1953  fn deref_mut(&mut self) -> &mut Self::Target {
1954    // SAFETY: we're just projecting the pinned reference, it still can't be moved
1955    unsafe { self.as_mut_ref().0.get_unchecked_mut().scope }
1956  }
1957}
1958
1959impl<'borrow, 'scope: 'borrow, 'obj: 'borrow, 'esc: 'obj, C> Deref
1960  for PinnedRef<
1961    '_,
1962    TryCatch<'borrow, 'scope, EscapableHandleScope<'obj, 'esc, C>>,
1963  >
1964{
1965  type Target = PinnedRef<'scope, EscapableHandleScope<'obj, 'esc, C>>;
1966
1967  fn deref(&self) -> &Self::Target {
1968    self.0.scope
1969  }
1970}
1971
1972impl<'borrow, 'scope: 'borrow, 'obj: 'borrow, 'esc: 'obj, C> DerefMut
1973  for PinnedRef<
1974    '_,
1975    TryCatch<'borrow, 'scope, EscapableHandleScope<'obj, 'esc, C>>,
1976  >
1977{
1978  fn deref_mut(&mut self) -> &mut Self::Target {
1979    // SAFETY: we're just projecting the pinned reference, it still can't be moved
1980    unsafe { self.0.as_mut().get_unchecked_mut().scope }
1981  }
1982}
1983
1984impl<'obj, P> Deref
1985  for PinnedRef<'_, DisallowJavascriptExecutionScope<'_, 'obj, P>>
1986{
1987  type Target = PinnedRef<'obj, P>;
1988  fn deref(&self) -> &Self::Target {
1989    self.0.scope
1990  }
1991}
1992
1993impl<P> DerefMut
1994  for PinnedRef<'_, DisallowJavascriptExecutionScope<'_, '_, P>>
1995{
1996  fn deref_mut(&mut self) -> &mut Self::Target {
1997    // SAFETY: we're just projecting the pinned reference, it still can't be moved
1998    unsafe { self.0.as_mut().get_unchecked_mut().scope }
1999  }
2000}
2001
2002impl<'obj, P> Deref
2003  for PinnedRef<'_, AllowJavascriptExecutionScope<'_, 'obj, P>>
2004{
2005  type Target = PinnedRef<'obj, P>;
2006  fn deref(&self) -> &Self::Target {
2007    self.0.scope
2008  }
2009}
2010impl<P> DerefMut for PinnedRef<'_, AllowJavascriptExecutionScope<'_, '_, P>> {
2011  fn deref_mut(&mut self) -> &mut Self::Target {
2012    // SAFETY: we're just projecting the pinned reference, it still can't be moved
2013    unsafe { self.0.as_mut().get_unchecked_mut().scope }
2014  }
2015}
2016
2017impl<P> GetIsolate for PinnedRef<'_, P>
2018where
2019  P: GetIsolate,
2020{
2021  fn get_isolate_ptr(&self) -> *mut RealIsolate {
2022    self.0.get_isolate_ptr()
2023  }
2024}
2025
2026impl<C> AsRef<Isolate> for PinnedRef<'_, HandleScope<'_, C>> {
2027  fn as_ref(&self) -> &Isolate {
2028    unsafe { Isolate::from_raw_ref(&self.0.isolate) }
2029  }
2030}
2031
2032impl<C> AsMut<Isolate> for PinnedRef<'_, HandleScope<'_, C>> {
2033  fn as_mut(&mut self) -> &mut Isolate {
2034    unsafe {
2035      Isolate::from_raw_ref_mut(
2036        &mut self.0.as_mut().get_unchecked_mut().isolate,
2037      )
2038    }
2039  }
2040}
2041
2042impl<C> AsRef<Isolate> for PinnedRef<'_, CallbackScope<'_, C>> {
2043  fn as_ref(&self) -> &Isolate {
2044    unsafe { Isolate::from_raw_ref(&self.0.isolate) }
2045  }
2046}
2047
2048impl<C> AsMut<Isolate> for PinnedRef<'_, CallbackScope<'_, C>> {
2049  fn as_mut(&mut self) -> &mut Isolate {
2050    unsafe {
2051      Isolate::from_raw_ref_mut(
2052        &mut self.0.as_mut().get_unchecked_mut().isolate,
2053      )
2054    }
2055  }
2056}
2057
2058impl<C> AsRef<Isolate> for PinnedRef<'_, TryCatch<'_, '_, HandleScope<'_, C>>> {
2059  fn as_ref(&self) -> &Isolate {
2060    unsafe { Isolate::from_raw_ref(&self.0.scope.0.isolate) }
2061  }
2062}
2063
2064impl<C> AsMut<Isolate> for PinnedRef<'_, TryCatch<'_, '_, HandleScope<'_, C>>> {
2065  fn as_mut(&mut self) -> &mut Isolate {
2066    unsafe {
2067      Isolate::from_raw_ref_mut(
2068        &mut self
2069          .0
2070          .as_mut()
2071          .get_unchecked_mut()
2072          .scope
2073          .0
2074          .as_mut()
2075          .get_unchecked_mut()
2076          .isolate,
2077      )
2078    }
2079  }
2080}
2081
2082impl<C> AsRef<Isolate>
2083  for PinnedRef<
2084    '_,
2085    DisallowJavascriptExecutionScope<'_, '_, HandleScope<'_, C>>,
2086  >
2087{
2088  fn as_ref(&self) -> &Isolate {
2089    unsafe { Isolate::from_raw_ref(&self.0.scope.0.isolate) }
2090  }
2091}
2092
2093impl<C> AsRef<Isolate>
2094  for PinnedRef<'_, AllowJavascriptExecutionScope<'_, '_, HandleScope<'_, C>>>
2095{
2096  fn as_ref(&self) -> &Isolate {
2097    unsafe { Isolate::from_raw_ref(&self.0.scope.0.isolate) }
2098  }
2099}
2100
2101impl AsRef<Isolate> for PinnedRef<'_, EscapableHandleScope<'_, '_>> {
2102  fn as_ref(&self) -> &Isolate {
2103    unsafe { Isolate::from_raw_ref(&self.0.isolate) }
2104  }
2105}
2106
2107impl<C> AsRef<Isolate> for ContextScope<'_, '_, HandleScope<'_, C>> {
2108  fn as_ref(&self) -> &Isolate {
2109    unsafe { Isolate::from_raw_ref(&self.scope.0.isolate) }
2110  }
2111}
2112impl<C> AsRef<Isolate> for ContextScope<'_, '_, CallbackScope<'_, C>> {
2113  fn as_ref(&self) -> &Isolate {
2114    unsafe { Isolate::from_raw_ref(&self.scope.0.isolate) }
2115  }
2116}
2117
2118impl<'pin, 's, 'esc: 's, C> AsRef<PinnedRef<'pin, HandleScope<'s, C>>>
2119  for PinnedRef<'pin, EscapableHandleScope<'s, 'esc, C>>
2120{
2121  fn as_ref(&self) -> &PinnedRef<'pin, HandleScope<'s, C>> {
2122    unsafe {
2123      cast_pinned_ref::<EscapableHandleScope<'s, 'esc, C>, HandleScope<'s, C>>(
2124        self,
2125      )
2126    }
2127  }
2128}
2129
2130impl<'obj, 'inner, C> AsRef<PinnedRef<'obj, HandleScope<'inner, C>>>
2131  for PinnedRef<'obj, HandleScope<'inner, C>>
2132{
2133  fn as_ref(&self) -> &PinnedRef<'obj, HandleScope<'inner, C>> {
2134    self
2135  }
2136}
2137
2138#[cfg(test)]
2139mod tests {
2140  use super::*;
2141  use crate::ContextOptions;
2142  use std::any::type_name;
2143  use std::pin::pin;
2144
2145  trait SameType {}
2146  impl<A> SameType for (A, A) {}
2147
2148  /// `AssertTypeOf` facilitates comparing types. The important difference with
2149  /// assigning a value to a variable with an explicitly stated type is that the
2150  /// latter allows coercions and dereferencing to change the type, whereas
2151  /// `AssertTypeOf` requires the compared types to match exactly.
2152  struct AssertTypeOf<'a, T>(#[allow(dead_code)] &'a T);
2153  impl<T> AssertTypeOf<'_, T> {
2154    pub fn is<A>(self)
2155    where
2156      (A, T): SameType,
2157    {
2158      assert_eq!(type_name::<A>(), type_name::<T>());
2159    }
2160  }
2161
2162  #[test]
2163  fn deref_types() {
2164    crate::initialize_v8();
2165    let isolate = &mut Isolate::new(Default::default());
2166    AssertTypeOf(isolate).is::<OwnedIsolate>();
2167    let l1_hs = pin!(HandleScope::new(isolate));
2168    let l1_hs = &mut l1_hs.init();
2169    AssertTypeOf(l1_hs).is::<PinnedRef<HandleScope<()>>>();
2170    let context = Context::new(l1_hs, ContextOptions::default());
2171    {
2172      let l2_cxs = &mut ContextScope::new(l1_hs, context);
2173      AssertTypeOf(l2_cxs).is::<ContextScope<HandleScope>>();
2174      {
2175        let d = l2_cxs.deref_mut();
2176        AssertTypeOf(d).is::<PinnedRef<HandleScope>>();
2177        let d = d.deref_mut();
2178        AssertTypeOf(d).is::<PinnedRef<HandleScope<()>>>();
2179        let d = d.deref_mut();
2180        AssertTypeOf(d).is::<Isolate>();
2181      }
2182      {
2183        tc_scope!(let l3_tc, &mut **l2_cxs);
2184        AssertTypeOf(l3_tc).is::<PinnedRef<TryCatch<HandleScope>>>();
2185        let d = l3_tc.deref_mut();
2186        AssertTypeOf(d).is::<PinnedRef<HandleScope>>();
2187        let d = d.deref_mut();
2188        AssertTypeOf(d).is::<PinnedRef<HandleScope<()>>>();
2189        let d = d.deref_mut();
2190        AssertTypeOf(d).is::<Isolate>();
2191      }
2192      {
2193        disallow_javascript_execution_scope!(let l3_djses, l2_cxs, OnFailure::CrashOnFailure);
2194        AssertTypeOf(l3_djses)
2195          .is::<PinnedRef<DisallowJavascriptExecutionScope<HandleScope>>>();
2196        let d = l3_djses.deref_mut();
2197        AssertTypeOf(d).is::<PinnedRef<HandleScope>>();
2198        let d = d.deref_mut();
2199        AssertTypeOf(d).is::<PinnedRef<HandleScope<()>>>();
2200        let d = d.deref_mut();
2201        AssertTypeOf(d).is::<Isolate>();
2202        {
2203          allow_javascript_execution_scope!(let l4_ajses, l3_djses);
2204          AssertTypeOf(l4_ajses).is::<PinnedRef<
2205            AllowJavascriptExecutionScope<
2206              DisallowJavascriptExecutionScope<HandleScope>,
2207            >,
2208          >>();
2209          let d = l4_ajses.deref_mut();
2210          AssertTypeOf(d)
2211            .is::<PinnedRef<DisallowJavascriptExecutionScope<HandleScope>>>();
2212          let d = d.deref_mut();
2213          AssertTypeOf(d).is::<PinnedRef<HandleScope>>();
2214          let d = d.deref_mut();
2215          AssertTypeOf(d).is::<PinnedRef<HandleScope<()>>>();
2216          let d = d.deref_mut();
2217          AssertTypeOf(d).is::<Isolate>();
2218        }
2219      }
2220      {
2221        escapable_handle_scope!(let l3_ehs, l2_cxs);
2222        AssertTypeOf(l3_ehs).is::<PinnedRef<EscapableHandleScope>>();
2223        {
2224          let l4_cxs = &mut ContextScope::new(l3_ehs, context);
2225          AssertTypeOf(l4_cxs).is::<ContextScope<EscapableHandleScope>>();
2226          let d = l4_cxs.deref_mut();
2227          AssertTypeOf(d).is::<PinnedRef<EscapableHandleScope>>();
2228          let d = d.deref_mut();
2229          AssertTypeOf(d).is::<PinnedRef<HandleScope>>();
2230          let d = d.deref_mut();
2231          AssertTypeOf(d).is::<PinnedRef<HandleScope<()>>>();
2232          let d = d.deref_mut();
2233          AssertTypeOf(d).is::<Isolate>();
2234        }
2235        {
2236          tc_scope!(let l4_tc, l3_ehs);
2237          AssertTypeOf(l4_tc).is::<PinnedRef<TryCatch<EscapableHandleScope>>>();
2238          let d = l4_tc.deref_mut();
2239          AssertTypeOf(d).is::<PinnedRef<EscapableHandleScope>>();
2240          let d = d.deref_mut();
2241          AssertTypeOf(d).is::<PinnedRef<HandleScope>>();
2242          let d = d.deref_mut();
2243          AssertTypeOf(d).is::<PinnedRef<HandleScope<()>>>();
2244          let d = d.deref_mut();
2245          AssertTypeOf(d).is::<Isolate>();
2246        }
2247        {
2248          disallow_javascript_execution_scope!(let l4_djses, l3_ehs, OnFailure::CrashOnFailure);
2249          AssertTypeOf(l4_djses)
2250            .is::<PinnedRef<DisallowJavascriptExecutionScope<EscapableHandleScope>>>();
2251          let d = l4_djses.deref_mut();
2252          AssertTypeOf(d).is::<PinnedRef<EscapableHandleScope>>();
2253          let d = d.deref_mut();
2254          AssertTypeOf(d).is::<PinnedRef<HandleScope>>();
2255          let d = d.deref_mut();
2256          AssertTypeOf(d).is::<PinnedRef<HandleScope<()>>>();
2257          let d = d.deref_mut();
2258          AssertTypeOf(d).is::<Isolate>();
2259          {
2260            allow_javascript_execution_scope!(let l5_ajses, l4_djses);
2261            AssertTypeOf(l5_ajses).is::<PinnedRef<
2262              AllowJavascriptExecutionScope<
2263                DisallowJavascriptExecutionScope<EscapableHandleScope>,
2264              >,
2265            >>();
2266            let d = l5_ajses.deref_mut();
2267            AssertTypeOf(d).is::<PinnedRef<DisallowJavascriptExecutionScope<EscapableHandleScope>>>();
2268            let d = d.deref_mut();
2269            AssertTypeOf(d).is::<PinnedRef<EscapableHandleScope>>();
2270            let d = d.deref_mut();
2271            AssertTypeOf(d).is::<PinnedRef<HandleScope>>();
2272            let d = d.deref_mut();
2273            AssertTypeOf(d).is::<PinnedRef<HandleScope<()>>>();
2274            let d = d.deref_mut();
2275            AssertTypeOf(d).is::<Isolate>();
2276          }
2277        }
2278      }
2279    }
2280    {
2281      tc_scope!(let l2_tc, l1_hs);
2282      AssertTypeOf(l2_tc).is::<PinnedRef<TryCatch<HandleScope<()>>>>();
2283      let d = l2_tc.deref_mut();
2284      AssertTypeOf(d).is::<PinnedRef<HandleScope<()>>>();
2285      let d = d.deref_mut();
2286      AssertTypeOf(d).is::<Isolate>();
2287      {
2288        disallow_javascript_execution_scope!(let l3_djses, l2_tc, OnFailure::CrashOnFailure);
2289        AssertTypeOf(l3_djses).is::<PinnedRef<
2290          DisallowJavascriptExecutionScope<TryCatch<HandleScope<()>>>,
2291        >>();
2292        let d = l3_djses.deref_mut();
2293        AssertTypeOf(d).is::<PinnedRef<TryCatch<HandleScope<()>>>>();
2294        let d = d.deref_mut();
2295        AssertTypeOf(d).is::<PinnedRef<HandleScope<()>>>();
2296        let d = d.deref_mut();
2297        AssertTypeOf(d).is::<Isolate>();
2298        {
2299          allow_javascript_execution_scope!(let l4_ajses, l3_djses);
2300          AssertTypeOf(l4_ajses).is::<PinnedRef<
2301            AllowJavascriptExecutionScope<
2302              DisallowJavascriptExecutionScope<TryCatch<HandleScope<()>>>,
2303            >,
2304          >>();
2305          let d = l4_ajses.deref_mut();
2306          AssertTypeOf(d).is::<PinnedRef<
2307            DisallowJavascriptExecutionScope<TryCatch<HandleScope<()>>>,
2308          >>();
2309          let d = d.deref_mut();
2310          AssertTypeOf(d).is::<PinnedRef<TryCatch<HandleScope<()>>>>();
2311          let d = d.deref_mut();
2312          AssertTypeOf(d).is::<PinnedRef<HandleScope<()>>>();
2313          let d = d.deref_mut();
2314          AssertTypeOf(d).is::<Isolate>();
2315        }
2316      }
2317    }
2318    {
2319      escapable_handle_scope!(let l2_ehs, l1_hs);
2320      AssertTypeOf(l2_ehs).is::<PinnedRef<EscapableHandleScope<()>>>();
2321      tc_scope!(let l3_tc, l2_ehs);
2322      AssertTypeOf(l3_tc).is::<PinnedRef<TryCatch<EscapableHandleScope<()>>>>();
2323      let d = l3_tc.deref_mut();
2324      AssertTypeOf(d).is::<PinnedRef<EscapableHandleScope<()>>>();
2325      let d = d.deref_mut();
2326      AssertTypeOf(d).is::<PinnedRef<HandleScope<()>>>();
2327      let d = d.deref_mut();
2328      AssertTypeOf(d).is::<Isolate>();
2329    }
2330    {
2331      // `CallbackScope` is meant to be used inside V8 API callback functions
2332      // only. It assumes that a `HandleScope` already exists on the stack, and
2333      // that a context has been entered. Push a `ContextScope` onto the stack
2334      // to also meet the second expectation.
2335      let _ = ContextScope::new(l1_hs, context);
2336      callback_scope!(unsafe l2_cbs, context);
2337      AssertTypeOf(l2_cbs).is::<PinnedRef<CallbackScope>>();
2338      let d = l2_cbs.deref_mut();
2339      AssertTypeOf(d).is::<PinnedRef<HandleScope>>();
2340      let d = d.deref_mut();
2341      AssertTypeOf(d).is::<PinnedRef<HandleScope<()>>>();
2342      let d = d.deref_mut();
2343      AssertTypeOf(d).is::<Isolate>();
2344    }
2345    {
2346      let isolate: &mut Isolate = l1_hs.as_mut();
2347      callback_scope!(unsafe l2_cbs, isolate);
2348      AssertTypeOf(l2_cbs).is::<PinnedRef<CallbackScope<()>>>();
2349      let d = l2_cbs.deref_mut();
2350      AssertTypeOf(d).is::<PinnedRef<HandleScope<()>>>();
2351      let d = d.deref_mut();
2352      AssertTypeOf(d).is::<Isolate>();
2353    }
2354  }
2355}