1use std::ptr;
2
3use crate::{bindgen_runtime::FromNapiValue, check_status, sys, Env, JsValue, Result};
4
5pub struct HandleScope {
6 pub(crate) scope: sys::napi_handle_scope,
7}
8
9impl HandleScope {
10 pub fn create(env: &Env) -> Result<Self> {
11 let mut scope = ptr::null_mut();
12 check_status!(
13 unsafe { sys::napi_open_handle_scope(env.0, &mut scope) },
14 "Failed to open handle scope"
15 )?;
16 Ok(Self { scope })
17 }
18
19 pub unsafe fn close<A, T>(self, arg: A, f: impl FnOnce(A) -> Result<T>) -> Result<T>
42 where
43 A: JsValuesTuple,
44 {
45 let env = arg.env();
46 let ret = f(arg);
47 check_status!(
48 unsafe { sys::napi_close_handle_scope(env, self.scope) },
49 "Failed to close handle scope"
50 )?;
51 ret
52 }
53}
54
55pub struct EscapableHandleScope<'env> {
56 pub(crate) scope: sys::napi_escapable_handle_scope,
57 pub(crate) env: sys::napi_env,
58 pub(crate) phantom: std::marker::PhantomData<&'env ()>,
59}
60
61impl<'env, 'scope: 'env> EscapableHandleScope<'scope> {
62 pub fn with<
63 T,
64 Args: JsValuesTuple,
65 F: 'env + FnOnce(EscapableHandleScope<'env>, Args) -> Result<T>,
66 >(
67 env: &'env Env,
68 args: Args,
69 scope_fn: F,
70 ) -> Result<T> {
71 let mut scope = ptr::null_mut();
72 check_status!(
73 unsafe { sys::napi_open_escapable_handle_scope(env.0, &mut scope) },
74 "Failed to open handle scope"
75 )?;
76 let scope: EscapableHandleScope<'env> = Self {
77 scope,
78 env: env.0,
79 phantom: std::marker::PhantomData,
80 };
81 scope_fn(scope, args)
82 }
83
84 pub fn escape<V: JsValue<'env> + FromNapiValue>(&self, value: V) -> Result<V> {
85 let mut result = ptr::null_mut();
86 check_status!(
87 unsafe { sys::napi_escape_handle(self.env, self.scope, value.raw(), &mut result) },
88 "Failed to escape handle"
89 )?;
90 unsafe { V::from_napi_value(self.env, result) }
91 }
92}
93
94impl Drop for EscapableHandleScope<'_> {
95 fn drop(&mut self) {
96 let status = unsafe { sys::napi_close_escapable_handle_scope(self.env, self.scope) };
97 if status != sys::Status::napi_ok {
98 panic!(
99 "Failed to close handle scope: {}",
100 crate::Status::from(status)
101 );
102 }
103 }
104}
105
106pub trait JsValuesTuple {
107 fn env(&self) -> sys::napi_env;
108}
109
110impl<'env, T: JsValue<'env>> JsValuesTuple for T {
111 fn env(&self) -> sys::napi_env {
112 self.value().env
113 }
114}
115
116impl<'env, T1: JsValue<'env>, T2: JsValue<'env>> JsValuesTuple for (T1, T2) {
117 fn env(&self) -> sys::napi_env {
118 self.0.value().env
119 }
120}
121
122impl<'env, T1: JsValue<'env>, T2: JsValue<'env>, T3: JsValue<'env>> JsValuesTuple for (T1, T2, T3) {
123 fn env(&self) -> sys::napi_env {
124 self.0.value().env
125 }
126}
127
128impl<'env, T1: JsValue<'env>, T2: JsValue<'env>, T3: JsValue<'env>, T4: JsValue<'env>> JsValuesTuple
129 for (T1, T2, T3, T4)
130{
131 fn env(&self) -> sys::napi_env {
132 self.0.value().env
133 }
134}
135
136impl<
137 'env,
138 T1: JsValue<'env>,
139 T2: JsValue<'env>,
140 T3: JsValue<'env>,
141 T4: JsValue<'env>,
142 T5: JsValue<'env>,
143 > JsValuesTuple for (T1, T2, T3, T4, T5)
144{
145 fn env(&self) -> sys::napi_env {
146 self.0.value().env
147 }
148}
149
150impl<
151 'env,
152 T1: JsValue<'env>,
153 T2: JsValue<'env>,
154 T3: JsValue<'env>,
155 T4: JsValue<'env>,
156 T5: JsValue<'env>,
157 T6: JsValue<'env>,
158 > JsValuesTuple for (T1, T2, T3, T4, T5, T6)
159{
160 fn env(&self) -> sys::napi_env {
161 self.0.value().env
162 }
163}
164
165impl<
166 'env,
167 T1: JsValue<'env>,
168 T2: JsValue<'env>,
169 T3: JsValue<'env>,
170 T4: JsValue<'env>,
171 T5: JsValue<'env>,
172 T6: JsValue<'env>,
173 T7: JsValue<'env>,
174 > JsValuesTuple for (T1, T2, T3, T4, T5, T6, T7)
175{
176 fn env(&self) -> sys::napi_env {
177 self.0.value().env
178 }
179}
180
181impl<
182 'env,
183 T1: JsValue<'env>,
184 T2: JsValue<'env>,
185 T3: JsValue<'env>,
186 T4: JsValue<'env>,
187 T5: JsValue<'env>,
188 T6: JsValue<'env>,
189 T7: JsValue<'env>,
190 T8: JsValue<'env>,
191 > JsValuesTuple for (T1, T2, T3, T4, T5, T6, T7, T8)
192{
193 fn env(&self) -> sys::napi_env {
194 self.0.value().env
195 }
196}
197
198impl<
199 'env,
200 T1: JsValue<'env>,
201 T2: JsValue<'env>,
202 T3: JsValue<'env>,
203 T4: JsValue<'env>,
204 T5: JsValue<'env>,
205 T6: JsValue<'env>,
206 T7: JsValue<'env>,
207 T8: JsValue<'env>,
208 T9: JsValue<'env>,
209 > JsValuesTuple for (T1, T2, T3, T4, T5, T6, T7, T8, T9)
210{
211 fn env(&self) -> sys::napi_env {
212 self.0.value().env
213 }
214}
215
216impl<
217 'env,
218 T1: JsValue<'env>,
219 T2: JsValue<'env>,
220 T3: JsValue<'env>,
221 T4: JsValue<'env>,
222 T5: JsValue<'env>,
223 T6: JsValue<'env>,
224 T7: JsValue<'env>,
225 T8: JsValue<'env>,
226 T9: JsValue<'env>,
227 T10: JsValue<'env>,
228 > JsValuesTuple for (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10)
229{
230 fn env(&self) -> sys::napi_env {
231 self.0.value().env
232 }
233}
234
235impl<
236 'env,
237 T1: JsValue<'env>,
238 T2: JsValue<'env>,
239 T3: JsValue<'env>,
240 T4: JsValue<'env>,
241 T5: JsValue<'env>,
242 T6: JsValue<'env>,
243 T7: JsValue<'env>,
244 T8: JsValue<'env>,
245 T9: JsValue<'env>,
246 T10: JsValue<'env>,
247 T11: JsValue<'env>,
248 > JsValuesTuple for (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11)
249{
250 fn env(&self) -> sys::napi_env {
251 self.0.value().env
252 }
253}
254
255impl<
256 'env,
257 T1: JsValue<'env>,
258 T2: JsValue<'env>,
259 T3: JsValue<'env>,
260 T4: JsValue<'env>,
261 T5: JsValue<'env>,
262 T6: JsValue<'env>,
263 T7: JsValue<'env>,
264 T8: JsValue<'env>,
265 T9: JsValue<'env>,
266 T10: JsValue<'env>,
267 T11: JsValue<'env>,
268 T12: JsValue<'env>,
269 > JsValuesTuple for (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12)
270{
271 fn env(&self) -> sys::napi_env {
272 self.0.value().env
273 }
274}