1#[cfg(all(debug_assertions, not(windows), not(target_family = "wasm")))]
2use std::collections::HashSet;
3use std::ffi::c_void;
4use std::mem;
5use std::ops::{Deref, DerefMut};
6use std::ptr::{self, NonNull};
7use std::slice;
8#[cfg(all(debug_assertions, not(windows), not(target_family = "wasm")))]
9use std::sync::Mutex;
10
11#[cfg(all(feature = "napi4", not(feature = "noop")))]
12use crate::bindgen_prelude::{CUSTOM_GC_TSFN, CUSTOM_GC_TSFN_DESTROYED, THREADS_CAN_ACCESS_ENV};
13use crate::{
14 bindgen_prelude::*, check_status, env::EMPTY_VEC, sys, JsValue, Result, Value, ValueType,
15};
16
17#[cfg(all(debug_assertions, not(windows), not(target_family = "wasm")))]
18thread_local! {
19 pub (crate) static BUFFER_DATA: Mutex<HashSet<*mut u8>> = Default::default();
20}
21
22pub struct BufferSlice<'env> {
28 pub(crate) inner: &'env mut [u8],
29 pub(crate) raw_value: sys::napi_value,
30 #[allow(dead_code)]
31 pub(crate) env: sys::napi_env,
32}
33
34impl<'env> BufferSlice<'env> {
35 pub fn from_data<D: Into<Vec<u8>>>(env: &Env, data: D) -> Result<Self> {
39 let mut buf = ptr::null_mut();
40 let mut data = data.into();
41 let inner_ptr = data.as_mut_ptr();
42 #[cfg(all(debug_assertions, not(windows), not(target_family = "wasm")))]
43 {
44 let is_existed = BUFFER_DATA.with(|buffer_data| {
45 let buffer = buffer_data.lock().expect("Unlock buffer data failed");
46 buffer.contains(&inner_ptr)
47 });
48 if is_existed {
49 panic!("Share the same data between different buffers is not allowed, see: https://github.com/nodejs/node/issues/32463#issuecomment-631974747");
50 }
51 }
52 let len = data.len();
53 let cap = data.capacity();
54 let finalize_hint = Box::into_raw(Box::new((len, cap)));
55 let mut status = unsafe {
56 sys::napi_create_external_buffer(
57 env.0,
58 len,
59 inner_ptr.cast(),
60 Some(drop_buffer_slice),
61 finalize_hint.cast(),
62 &mut buf,
63 )
64 };
65 if status == sys::Status::napi_no_external_buffers_allowed {
66 unsafe {
67 let _ = Box::from_raw(finalize_hint);
68 }
69 status = unsafe {
70 sys::napi_create_buffer_copy(
71 env.0,
72 len,
73 data.as_mut_ptr().cast(),
74 ptr::null_mut(),
75 &mut buf,
76 )
77 };
78 } else {
79 mem::forget(data);
80 }
81 check_status!(status, "Failed to create buffer slice from data")?;
82
83 Ok(Self {
84 inner: if len == 0 {
85 &mut []
86 } else {
87 unsafe { slice::from_raw_parts_mut(buf.cast(), len) }
88 },
89 raw_value: buf,
90 env: env.0,
91 })
92 }
93
94 pub unsafe fn from_external<T: 'env, F: FnOnce(Env, T)>(
114 env: &Env,
115 data: *mut u8,
116 len: usize,
117 finalize_hint: T,
118 finalize_callback: F,
119 ) -> Result<Self> {
120 let mut buf = ptr::null_mut();
121 if data.is_null() || std::ptr::eq(data, EMPTY_VEC.as_ptr()) {
122 return Err(Error::new(
123 Status::InvalidArg,
124 "Borrowed data should not be null".to_owned(),
125 ));
126 }
127 #[cfg(all(debug_assertions, not(windows), not(target_family = "wasm")))]
128 {
129 let is_existed = BUFFER_DATA.with(|buffer_data| {
130 let buffer = buffer_data.lock().expect("Unlock buffer data failed");
131 buffer.contains(&data)
132 });
133 if is_existed {
134 panic!("Share the same data between different buffers is not allowed, see: https://github.com/nodejs/node/issues/32463#issuecomment-631974747");
135 }
136 }
137 let hint_ptr = Box::into_raw(Box::new((finalize_hint, finalize_callback)));
138 let mut status = unsafe {
139 sys::napi_create_external_buffer(
140 env.0,
141 len,
142 data.cast(),
143 Some(crate::env::raw_finalize_with_custom_callback::<T, F>),
144 hint_ptr.cast(),
145 &mut buf,
146 )
147 };
148 status = if status == sys::Status::napi_no_external_buffers_allowed {
149 let (hint, finalize) = *Box::from_raw(hint_ptr);
150 let status =
151 unsafe { sys::napi_create_buffer_copy(env.0, len, data.cast(), ptr::null_mut(), &mut buf) };
152 finalize(*env, hint);
153 status
154 } else {
155 status
156 };
157 check_status!(status, "Failed to create buffer slice from data")?;
158
159 Ok(Self {
160 inner: if len == 0 {
161 &mut []
162 } else {
163 unsafe { slice::from_raw_parts_mut(buf.cast(), len) }
164 },
165 raw_value: buf,
166 env: env.0,
167 })
168 }
169
170 pub fn copy_from<D: AsRef<[u8]>>(env: &Env, data: D) -> Result<Self> {
172 let data = data.as_ref();
173 let len = data.len();
174 let data_ptr = data.as_ptr();
175 let mut buf = ptr::null_mut();
176 let mut result_ptr = ptr::null_mut();
177 check_status!(
178 unsafe {
179 sys::napi_create_buffer_copy(env.0, len, data_ptr.cast(), &mut result_ptr, &mut buf)
180 },
181 "Faild to create a buffer from copied data"
182 )?;
183 Ok(Self {
184 inner: if len == 0 {
185 &mut []
186 } else {
187 unsafe { slice::from_raw_parts_mut(buf.cast(), len) }
188 },
189 raw_value: buf,
190 env: env.0,
191 })
192 }
193
194 pub fn into_buffer(self, env: &Env) -> Result<Buffer> {
198 unsafe { Buffer::from_napi_value(env.0, self.raw_value) }
199 }
200}
201
202impl<'env> JsValue<'env> for BufferSlice<'env> {
203 fn value(&self) -> Value {
204 Value {
205 env: self.env,
206 value: self.raw_value,
207 value_type: ValueType::Object,
208 }
209 }
210}
211
212impl<'env> JsObjectValue<'env> for BufferSlice<'env> {}
213
214impl FromNapiValue for BufferSlice<'_> {
215 unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
216 let mut buf = ptr::null_mut();
217 let mut len = 0usize;
218 check_status!(
219 unsafe { sys::napi_get_buffer_info(env, napi_val, &mut buf, &mut len) },
220 "Failed to get Buffer pointer and length"
221 )?;
222 Ok(Self {
230 inner: if len == 0 {
231 &mut []
232 } else {
233 unsafe { slice::from_raw_parts_mut(buf.cast(), len) }
234 },
235 raw_value: napi_val,
236 env,
237 })
238 }
239}
240
241impl ToNapiValue for &BufferSlice<'_> {
242 #[allow(unused_variables)]
243 unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
244 Ok(val.raw_value)
245 }
246}
247
248impl TypeName for BufferSlice<'_> {
249 fn type_name() -> &'static str {
250 "Buffer"
251 }
252
253 fn value_type() -> ValueType {
254 ValueType::Object
255 }
256}
257
258impl ValidateNapiValue for BufferSlice<'_> {
259 unsafe fn validate(env: sys::napi_env, napi_val: sys::napi_value) -> Result<sys::napi_value> {
260 let mut is_buffer = false;
261 check_status!(
262 unsafe { sys::napi_is_buffer(env, napi_val, &mut is_buffer) },
263 "Failed to validate napi buffer"
264 )?;
265 if !is_buffer {
266 return Err(Error::new(
267 Status::InvalidArg,
268 "Expected a Buffer value".to_owned(),
269 ));
270 }
271 Ok(ptr::null_mut())
272 }
273}
274
275impl AsRef<[u8]> for BufferSlice<'_> {
276 fn as_ref(&self) -> &[u8] {
277 self.inner
278 }
279}
280
281impl Deref for BufferSlice<'_> {
282 type Target = [u8];
283
284 fn deref(&self) -> &Self::Target {
285 self.inner
286 }
287}
288
289impl DerefMut for BufferSlice<'_> {
290 fn deref_mut(&mut self) -> &mut Self::Target {
291 self.inner
292 }
293}
294
295pub struct Buffer {
303 pub(crate) inner: NonNull<u8>,
304 pub(crate) len: usize,
305 pub(crate) capacity: usize,
306 raw: Option<(sys::napi_ref, sys::napi_env)>,
307}
308
309impl Drop for Buffer {
310 fn drop(&mut self) {
311 if let Some((ref_, env)) = self.raw {
312 if ref_.is_null() {
313 return;
314 }
315 #[cfg(all(feature = "napi4", not(feature = "noop")))]
320 {
321 if CUSTOM_GC_TSFN_DESTROYED.load(std::sync::atomic::Ordering::SeqCst) {
322 return;
323 }
324 if !THREADS_CAN_ACCESS_ENV.with(|cell| cell.get()) {
326 let status = unsafe {
327 sys::napi_call_threadsafe_function(
328 CUSTOM_GC_TSFN.load(std::sync::atomic::Ordering::SeqCst),
329 ref_.cast(),
330 1,
331 )
332 };
333 assert!(
334 status == sys::Status::napi_ok || status == sys::Status::napi_closing,
335 "Call custom GC in Buffer::drop failed {}",
336 Status::from(status)
337 );
338 return;
339 }
340 }
341 let mut ref_count = 0;
342 check_status_or_throw!(
343 env,
344 unsafe { sys::napi_reference_unref(env, ref_, &mut ref_count) },
345 "Failed to unref Buffer reference in drop"
346 );
347 debug_assert!(
348 ref_count == 0,
349 "Buffer reference count in Buffer::drop is not zero"
350 );
351 check_status_or_throw!(
352 env,
353 unsafe { sys::napi_delete_reference(env, ref_) },
354 "Failed to delete Buffer reference in drop"
355 );
356 } else {
357 unsafe { Vec::from_raw_parts(self.inner.as_ptr(), self.len, self.capacity) };
358 }
359 }
360}
361
362unsafe impl Send for Buffer {}
365unsafe impl Sync for Buffer {}
366
367impl Default for Buffer {
368 fn default() -> Self {
369 Self::from(Vec::default())
370 }
371}
372
373impl From<Vec<u8>> for Buffer {
374 fn from(mut data: Vec<u8>) -> Self {
375 let inner_ptr = data.as_mut_ptr();
376 #[cfg(all(debug_assertions, not(windows), not(target_family = "wasm")))]
377 {
378 let is_existed = BUFFER_DATA.with(|buffer_data| {
379 let buffer = buffer_data.lock().expect("Unlock buffer data failed");
380 buffer.contains(&inner_ptr)
381 });
382 if is_existed {
383 panic!("Share the same data between different buffers is not allowed, see: https://github.com/nodejs/node/issues/32463#issuecomment-631974747");
384 }
385 }
386 let len = data.len();
387 let capacity = data.capacity();
388 mem::forget(data);
389 Buffer {
390 inner: unsafe { NonNull::new_unchecked(inner_ptr) },
394 len,
395 capacity,
396 raw: None,
397 }
398 }
399}
400
401impl From<Buffer> for Vec<u8> {
402 fn from(buf: Buffer) -> Self {
403 buf.as_ref().to_vec()
404 }
405}
406
407impl From<&[u8]> for Buffer {
408 fn from(inner: &[u8]) -> Self {
409 Buffer::from(inner.to_owned())
410 }
411}
412
413impl From<String> for Buffer {
414 fn from(inner: String) -> Self {
415 Buffer::from(inner.into_bytes())
416 }
417}
418
419impl AsRef<[u8]> for Buffer {
420 fn as_ref(&self) -> &[u8] {
421 unsafe { slice::from_raw_parts(self.inner.as_ptr(), self.len) }
423 }
424}
425
426impl AsMut<[u8]> for Buffer {
427 fn as_mut(&mut self) -> &mut [u8] {
428 unsafe { slice::from_raw_parts_mut(self.inner.as_ptr(), self.len) }
432 }
433}
434
435impl Deref for Buffer {
436 type Target = [u8];
437
438 fn deref(&self) -> &Self::Target {
439 self.as_ref()
440 }
441}
442
443impl DerefMut for Buffer {
444 fn deref_mut(&mut self) -> &mut Self::Target {
445 self.as_mut()
446 }
447}
448
449impl TypeName for Buffer {
450 fn type_name() -> &'static str {
451 "Vec<u8>"
452 }
453
454 fn value_type() -> ValueType {
455 ValueType::Object
456 }
457}
458
459impl FromNapiValue for Buffer {
460 unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
461 let mut buf = ptr::null_mut();
462 let mut len = 0;
463 let mut ref_ = ptr::null_mut();
464 check_status!(
465 unsafe { sys::napi_create_reference(env, napi_val, 1, &mut ref_) },
466 "Failed to create reference from Buffer"
467 )?;
468 check_status!(
469 unsafe { sys::napi_get_buffer_info(env, napi_val, &mut buf, &mut len as *mut usize) },
470 "Failed to get Buffer pointer and length"
471 )?;
472
473 let buf = NonNull::new(buf as *mut u8);
481 let inner = match buf {
482 Some(buf) if len != 0 => buf,
483 _ => NonNull::dangling(),
484 };
485
486 Ok(Self {
487 inner,
488 len,
489 capacity: len,
490 raw: Some((ref_, env)),
491 })
492 }
493}
494
495impl ToNapiValue for Buffer {
496 unsafe fn to_napi_value(env: sys::napi_env, mut val: Self) -> Result<sys::napi_value> {
497 if let Some((ref_, _)) = val.raw {
499 let mut buf = ptr::null_mut();
500 check_status!(
501 unsafe { sys::napi_get_reference_value(env, ref_, &mut buf) },
502 "Failed to get Buffer value from reference"
503 )?;
504
505 check_status!(
506 unsafe { sys::napi_delete_reference(env, ref_) },
507 "Failed to delete Buffer reference in Buffer::to_napi_value"
508 )?;
509 val.raw = Some((ptr::null_mut(), ptr::null_mut()));
510 return Ok(buf);
511 }
512 let len = val.len;
513 let mut ret = ptr::null_mut();
514 check_status!(
515 if len == 0 {
516 unsafe { sys::napi_create_buffer(env, len, ptr::null_mut(), &mut ret) }
520 } else {
521 let value_ptr = val.inner.as_ptr();
522 let val_box_ptr = Box::into_raw(Box::new(val));
523 let mut status = unsafe {
524 sys::napi_create_external_buffer(
525 env,
526 len,
527 value_ptr.cast(),
528 Some(drop_buffer),
529 val_box_ptr.cast(),
530 &mut ret,
531 )
532 };
533 if status == napi_sys::Status::napi_no_external_buffers_allowed {
534 let value = unsafe { Box::from_raw(val_box_ptr) };
535 status = unsafe {
536 sys::napi_create_buffer_copy(
537 env,
538 len,
539 value.inner.as_ptr() as *mut c_void,
540 ptr::null_mut(),
541 &mut ret,
542 )
543 };
544 }
545 status
546 },
547 "Failed to create napi buffer"
548 )?;
549
550 Ok(ret)
551 }
552}
553
554impl ValidateNapiValue for Buffer {
555 unsafe fn validate(env: sys::napi_env, napi_val: sys::napi_value) -> Result<sys::napi_value> {
556 let mut is_buffer = false;
557 check_status!(
558 unsafe { sys::napi_is_buffer(env, napi_val, &mut is_buffer) },
559 "Failed to validate napi buffer"
560 )?;
561 if !is_buffer {
562 return Err(Error::new(
563 Status::InvalidArg,
564 "Expected a Buffer value".to_owned(),
565 ));
566 }
567 Ok(ptr::null_mut())
568 }
569}