nodex_api/scope/
handle.rs

1use crate::{api, prelude::*};
2use std::mem::MaybeUninit;
3
4/// Node-API provides the ability to establish a new 'scope' to which newly created handles
5/// will be associated. Once those handles are no longer required, the scope can be 'closed'
6/// and any handles associated with the scope are invalidated. The methods available to
7/// open/close scopes are napi_open_handle_scope and napi_close_handle_scope.
8///
9/// Node-API only supports a single nested hierarchy of scopes. There is only one active scope
10/// at any time, and all new handles will be associated with that scope while it is active.
11/// Scopes must be closed in the reverse order from which they are opened. In addition,
12/// all scopes created within a native method must be closed before returning from that method.
13#[derive(Clone, Debug)]
14pub struct NapiHandleScope(NapiEnv, napi_handle_scope);
15
16impl NapiHandleScope {
17    pub(crate) fn from_raw(env: NapiEnv, handle: napi_handle_scope) -> NapiHandleScope {
18        NapiHandleScope(env, handle)
19    }
20
21    pub fn env(&self) -> NapiEnv {
22        self.0
23    }
24
25    pub fn raw(&self) -> napi_handle_scope {
26        self.1
27    }
28
29    /// This API opens a new scope.
30    pub fn open(env: NapiEnv) -> NapiResult<NapiHandleScope> {
31        let handle = napi_call!(=napi_open_handle_scope, env);
32        Ok(NapiHandleScope(env, handle))
33    }
34
35    /// This API closes the scope passed in. Scopes must be closed in the reverse
36    /// order from which they were created.
37    /// This API can be called even if there is a pending JavaScript exception.
38    pub fn close(&mut self) -> NapiResult<()> {
39        napi_call!(napi_close_handle_scope, self.env(), self.raw())
40    }
41}
42
43impl Drop for NapiHandleScope {
44    fn drop(&mut self) {
45        if let Err(e) = self.close() {
46            log::warn!("[{}] napi_close_handle_scope failed.", e);
47        }
48    }
49}
50
51/// When nesting scopes, there are cases where a handle from an inner scope needs to live
52/// beyond the lifespan of that scope. Node-API supports an 'escapable scope' in order to
53/// support this case. An escapable scope allows one handle to be 'promoted' so that it
54/// 'escapes' the current scope and the lifespan of the handle changes from the current scope
55/// to that of the outer scope.
56///
57/// The methods available to open/close escapable scopes are napi_open_escapable_handle_scope
58/// and napi_close_escapable_handle_scope.
59///
60/// The request to promote a handle is made through napi_escape_handle which can only be
61/// called once.
62#[derive(Clone, Debug)]
63pub struct NapiEscapableHandleScope(NapiEnv, napi_escapable_handle_scope);
64
65impl NapiEscapableHandleScope {
66    pub(crate) fn from_value(
67        env: NapiEnv,
68        handle: napi_escapable_handle_scope,
69    ) -> NapiEscapableHandleScope {
70        NapiEscapableHandleScope(env, handle)
71    }
72
73    pub fn env(&self) -> NapiEnv {
74        self.0
75    }
76
77    pub fn raw(&self) -> napi_escapable_handle_scope {
78        self.1
79    }
80
81    /// This API opens a new scope from which one object can be promoted to the outer scope.
82    pub fn open(env: NapiEnv) -> NapiResult<NapiEscapableHandleScope> {
83        let handle = napi_call!(=napi_open_escapable_handle_scope, env);
84        Ok(NapiEscapableHandleScope(env, handle))
85    }
86
87    /// This API closes the scope passed in. Scopes must be closed in the reverse
88    /// order from which they were created.
89    /// This API can be called even if there is a pending JavaScript exception.
90    pub fn close(&mut self) -> NapiResult<()> {
91        napi_call!(napi_close_escapable_handle_scope, self.env(), self.raw())
92    }
93
94    /// This API promotes the handle to the JavaScript object so that it is valid for
95    /// the lifetime of the outer scope. It can only be called once per scope. If it is
96    /// called more than once an error will be returned.
97    ///
98    /// This API can be called even if there is a pending JavaScript exception.
99    pub fn escape<T: NapiValueT>(&mut self, escapee: T) -> NapiResult<T> {
100        let escapee = napi_call!(=napi_escape_handle, self.env(), self.1, escapee.raw());
101        Ok(T::from_raw(self.env(), escapee))
102    }
103}
104
105impl Drop for NapiEscapableHandleScope {
106    fn drop(&mut self) {
107        if let Err(e) = self.close() {
108            log::warn!("[{}] napi_close_escapable_handle_scope failed.", e);
109        }
110    }
111}