1use libc::INT_MAX;
3
4use crate::*;
5
6#[repr(transparent)]
7pub(crate) struct SendPtr<T>(pub *const T);
8
9impl<T> SendPtr<T> {
10 pub fn take(self) -> *const T {
12 self.0
13 }
14}
15
16unsafe impl<T> Send for SendPtr<T> {}
17unsafe impl<T> Sync for SendPtr<T> {}
18
19pub fn get_array_buffer_ptr(ab: v8::Local<v8::ArrayBuffer>) -> *mut c_void {
20 match ab.data() {
21 Some(p) => p.as_ptr(),
22 None => std::ptr::null_mut(),
23 }
24}
25
26struct BufferFinalizer {
27 env: *mut Env,
28 finalize_cb: Option<napi_finalize>,
29 finalize_data: *mut c_void,
30 finalize_hint: *mut c_void,
31}
32
33impl Drop for BufferFinalizer {
34 fn drop(&mut self) {
35 if let Some(finalize_cb) = self.finalize_cb {
36 unsafe {
37 finalize_cb(self.env as _, self.finalize_data, self.finalize_hint);
38 }
39 }
40 }
41}
42
43pub(crate) extern "C" fn backing_store_deleter_callback(
44 data: *mut c_void,
45 _byte_length: usize,
46 deleter_data: *mut c_void,
47) {
48 let mut finalizer =
49 unsafe { Box::<BufferFinalizer>::from_raw(deleter_data as _) };
50
51 finalizer.finalize_data = data;
52
53 drop(finalizer);
54}
55
56pub(crate) fn make_external_backing_store(
57 env: *mut Env,
58 data: *mut c_void,
59 byte_length: usize,
60 finalize_data: *mut c_void,
61 finalize_cb: Option<napi_finalize>,
62 finalize_hint: *mut c_void,
63) -> v8::UniqueRef<v8::BackingStore> {
64 let finalizer = Box::new(BufferFinalizer {
65 env,
66 finalize_data,
67 finalize_cb,
68 finalize_hint,
69 });
70
71 unsafe {
72 v8::ArrayBuffer::new_backing_store_from_ptr(
73 data,
74 byte_length,
75 backing_store_deleter_callback,
76 Box::into_raw(finalizer) as _,
77 )
78 }
79}
80
81#[macro_export]
82macro_rules! check_env {
83 ($env: expr) => {{
84 let env = $env;
85 if env.is_null() {
86 return napi_invalid_arg;
87 }
88 unsafe { &mut *env }
89 }};
90}
91
92#[macro_export]
93macro_rules! return_error_status_if_false {
94 ($env: expr, $condition: expr, $status: ident) => {
95 if !$condition {
96 return Err($crate::util::napi_set_last_error($env, $status).into());
97 }
98 };
99}
100
101#[macro_export]
102macro_rules! return_status_if_false {
103 ($env: expr, $condition: expr, $status: ident) => {
104 if !$condition {
105 return $crate::util::napi_set_last_error($env, $status);
106 }
107 };
108}
109
110pub(crate) unsafe fn check_new_from_utf8_len<'s>(
111 env: *mut Env,
112 str_: *const c_char,
113 len: usize,
114) -> Result<v8::Local<'s, v8::String>, napi_status> {
115 let env = unsafe { &mut *env };
116 return_error_status_if_false!(
117 env,
118 (len == NAPI_AUTO_LENGTH) || len <= INT_MAX as _,
119 napi_invalid_arg
120 );
121 return_error_status_if_false!(env, !str_.is_null(), napi_invalid_arg);
122 let string = if len == NAPI_AUTO_LENGTH {
123 unsafe { std::ffi::CStr::from_ptr(str_ as *const _) }.to_bytes()
124 } else {
125 unsafe { std::slice::from_raw_parts(str_ as *const u8, len) }
126 };
127 let result = {
128 let env = unsafe { &mut *(env as *mut Env) };
129 v8::callback_scope!(unsafe scope, env.context());
130 v8::String::new_from_utf8(scope, string, v8::NewStringType::Internalized)
131 };
132 return_error_status_if_false!(env, result.is_some(), napi_generic_failure);
133 Ok(result.unwrap())
134}
135
136#[inline]
137pub(crate) unsafe fn check_new_from_utf8<'s>(
138 env: *mut Env,
139 str_: *const c_char,
140) -> Result<v8::Local<'s, v8::String>, napi_status> {
141 unsafe { check_new_from_utf8_len(env, str_, NAPI_AUTO_LENGTH) }
142}
143
144pub(crate) unsafe fn v8_name_from_property_descriptor<'s>(
145 env: *mut Env,
146 p: &'s napi_property_descriptor,
147) -> Result<v8::Local<'s, v8::Name>, napi_status> {
148 if !p.utf8name.is_null() {
149 unsafe { check_new_from_utf8(env, p.utf8name).map(|v| v.into()) }
150 } else {
151 match *p.name {
152 Some(v) => match v.try_into() {
153 Ok(name) => Ok(name),
154 Err(_) => Err(napi_name_expected),
155 },
156 None => Err(napi_name_expected),
157 }
158 }
159}
160
161pub(crate) fn napi_clear_last_error(env: *mut Env) -> napi_status {
162 let env = unsafe { &mut *env };
163 env.last_error.error_code.set(napi_ok);
164 env.last_error.engine_error_code = 0;
165 env.last_error.engine_reserved = std::ptr::null_mut();
166 env.last_error.error_message = std::ptr::null_mut();
167 napi_ok
168}
169
170pub(crate) fn napi_set_last_error(
171 env: *const Env,
172 error_code: napi_status,
173) -> napi_status {
174 let env = unsafe { &*env };
175 env.last_error.error_code.set(error_code);
176 error_code
177}
178
179#[macro_export]
180macro_rules! status_call {
181 ($call: expr) => {
182 let status = $call;
183 if status != napi_ok {
184 return status;
185 }
186 };
187}
188
189pub trait Nullable {
190 fn is_null(&self) -> bool;
191}
192
193impl<T> Nullable for *mut T {
194 fn is_null(&self) -> bool {
195 (*self).is_null()
196 }
197}
198
199impl<T> Nullable for *const T {
200 fn is_null(&self) -> bool {
201 (*self).is_null()
202 }
203}
204
205impl<T> Nullable for Option<T> {
206 fn is_null(&self) -> bool {
207 self.is_none()
208 }
209}
210
211impl Nullable for napi_value<'_> {
212 fn is_null(&self) -> bool {
213 self.is_none()
214 }
215}
216
217#[macro_export]
218macro_rules! check_arg {
219 ($env: expr, $ptr: expr) => {
220 $crate::return_status_if_false!(
221 $env,
222 !$crate::util::Nullable::is_null(&$ptr),
223 napi_invalid_arg
224 );
225 };
226}
227
228#[macro_export]
229macro_rules! napi_wrap {
230 ( $( # [ $attr:meta ] )* $vis:vis fn $name:ident $( < $( $x:lifetime ),* > )? ( $env:ident : & $( $lt:lifetime )? mut Env $( , $ident:ident : $ty:ty )* $(,)? ) -> napi_status $body:block ) => {
231 $( # [ $attr ] )*
232 #[unsafe(no_mangle)]
233 $vis unsafe extern "C" fn $name $( < $( $x ),* > )? ( env_ptr : *mut Env , $( $ident : $ty ),* ) -> napi_status {
234 let env: & $( $lt )? mut Env = $crate::check_env!(env_ptr);
235
236 if env.last_exception.is_some() {
237 return napi_pending_exception;
238 }
239
240 $crate::util::napi_clear_last_error(env);
241
242 let scope_env = unsafe { &mut *env_ptr };
243 deno_core::v8::callback_scope!(unsafe scope, scope_env.context());
244 deno_core::v8::tc_scope!(try_catch, scope);
245
246 #[inline(always)]
247 fn inner $( < $( $x ),* > )? ( $env: & $( $lt )? mut Env , $( $ident : $ty ),* ) -> napi_status $body
248
249 #[cfg(debug_assertions)]
250 log::trace!("NAPI ENTER: {}", stringify!($name));
251
252 let result = inner( env, $( $ident ),* );
253
254 #[cfg(debug_assertions)]
255 log::trace!("NAPI EXIT: {} {}", stringify!($name), result);
256
257 if let Some(exception) = try_catch.exception() {
258 let env = unsafe { &mut *env_ptr };
259 let global = v8::Global::new(env.isolate(), exception);
260 env.last_exception = Some(global);
261 return $crate::util::napi_set_last_error(env_ptr, napi_pending_exception);
262 }
263
264 if result != napi_ok {
265 return $crate::util::napi_set_last_error(env_ptr, result);
266 }
267
268 return result;
269 }
270 };
271
272 ( $( # [ $attr:meta ] )* $vis:vis fn $name:ident $( < $( $x:lifetime ),* > )? ( $( $ident:ident : $ty:ty ),* $(,)? ) -> napi_status $body:block ) => {
273 $( # [ $attr ] )*
274 #[unsafe(no_mangle)]
275 $vis unsafe extern "C" fn $name $( < $( $x ),* > )? ( $( $ident : $ty ),* ) -> napi_status {
276 #[inline(always)]
277 fn inner $( < $( $x ),* > )? ( $( $ident : $ty ),* ) -> napi_status $body
278
279 #[cfg(debug_assertions)]
280 log::trace!("NAPI ENTER: {}", stringify!($name));
281
282 let result = inner( $( $ident ),* );
283
284 #[cfg(debug_assertions)]
285 log::trace!("NAPI EXIT: {} {}", stringify!($name), result);
286
287 result
288 }
289 };
290}