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