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)>(
111 env: &Env,
112 data: *mut u8,
113 len: usize,
114 finalize_hint: T,
115 finalize_callback: F,
116 ) -> Result<Self> {
117 let mut buf = ptr::null_mut();
118 if data.is_null() || std::ptr::eq(data, EMPTY_VEC.as_ptr()) {
119 return Err(Error::new(
120 Status::InvalidArg,
121 "Borrowed data should not be null".to_owned(),
122 ));
123 }
124 #[cfg(all(debug_assertions, not(windows), not(target_family = "wasm")))]
125 {
126 let is_existed = BUFFER_DATA.with(|buffer_data| {
127 let buffer = buffer_data.lock().expect("Unlock buffer data failed");
128 buffer.contains(&data)
129 });
130 if is_existed {
131 panic!("Share the same data between different buffers is not allowed, see: https://github.com/nodejs/node/issues/32463#issuecomment-631974747");
132 }
133 }
134 let hint_ptr = Box::into_raw(Box::new((finalize_hint, finalize_callback)));
135 let mut status = unsafe {
136 sys::napi_create_external_buffer(
137 env.0,
138 len,
139 data.cast(),
140 Some(crate::env::raw_finalize_with_custom_callback::<T, F>),
141 hint_ptr.cast(),
142 &mut buf,
143 )
144 };
145 status = if status == sys::Status::napi_no_external_buffers_allowed {
146 let (hint, finalize) = *Box::from_raw(hint_ptr);
147 let status =
148 unsafe { sys::napi_create_buffer_copy(env.0, len, data.cast(), ptr::null_mut(), &mut buf) };
149 finalize(*env, hint);
150 status
151 } else {
152 status
153 };
154 check_status!(status, "Failed to create buffer slice from data")?;
155
156 Ok(Self {
157 inner: if len == 0 {
158 &mut []
159 } else {
160 unsafe { slice::from_raw_parts_mut(buf.cast(), len) }
161 },
162 raw_value: buf,
163 env: env.0,
164 })
165 }
166
167 pub fn copy_from<D: AsRef<[u8]>>(env: &Env, data: D) -> Result<Self> {
169 let data = data.as_ref();
170 let len = data.len();
171 let data_ptr = data.as_ptr();
172 let mut buf = ptr::null_mut();
173 let mut result_ptr = ptr::null_mut();
174 check_status!(
175 unsafe {
176 sys::napi_create_buffer_copy(env.0, len, data_ptr.cast(), &mut result_ptr, &mut buf)
177 },
178 "Faild to create a buffer from copied data"
179 )?;
180 Ok(Self {
181 inner: if len == 0 {
182 &mut []
183 } else {
184 unsafe { slice::from_raw_parts_mut(buf.cast(), len) }
185 },
186 raw_value: buf,
187 env: env.0,
188 })
189 }
190
191 pub fn into_buffer(self, env: &Env) -> Result<Buffer> {
195 unsafe { Buffer::from_napi_value(env.0, self.raw_value) }
196 }
197}
198
199impl<'env> JsValue<'env> for BufferSlice<'env> {
200 fn value(&self) -> Value {
201 Value {
202 env: self.env,
203 value: self.raw_value,
204 value_type: ValueType::Object,
205 }
206 }
207}
208
209impl<'env> JsObjectValue<'env> for BufferSlice<'env> {}
210
211impl FromNapiValue for BufferSlice<'_> {
212 unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
213 let mut buf = ptr::null_mut();
214 let mut len = 0usize;
215 check_status!(
216 unsafe { sys::napi_get_buffer_info(env, napi_val, &mut buf, &mut len) },
217 "Failed to get Buffer pointer and length"
218 )?;
219 Ok(Self {
227 inner: if len == 0 {
228 &mut []
229 } else {
230 unsafe { slice::from_raw_parts_mut(buf.cast(), len) }
231 },
232 raw_value: napi_val,
233 env,
234 })
235 }
236}
237
238impl ToNapiValue for &BufferSlice<'_> {
239 #[allow(unused_variables)]
240 unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
241 Ok(val.raw_value)
242 }
243}
244
245impl TypeName for BufferSlice<'_> {
246 fn type_name() -> &'static str {
247 "Buffer"
248 }
249
250 fn value_type() -> ValueType {
251 ValueType::Object
252 }
253}
254
255impl ValidateNapiValue for BufferSlice<'_> {
256 unsafe fn validate(env: sys::napi_env, napi_val: sys::napi_value) -> Result<sys::napi_value> {
257 let mut is_buffer = false;
258 check_status!(
259 unsafe { sys::napi_is_buffer(env, napi_val, &mut is_buffer) },
260 "Failed to validate napi buffer"
261 )?;
262 if !is_buffer {
263 return Err(Error::new(
264 Status::InvalidArg,
265 "Expected a Buffer value".to_owned(),
266 ));
267 }
268 Ok(ptr::null_mut())
269 }
270}
271
272impl AsRef<[u8]> for BufferSlice<'_> {
273 fn as_ref(&self) -> &[u8] {
274 self.inner
275 }
276}
277
278impl Deref for BufferSlice<'_> {
279 type Target = [u8];
280
281 fn deref(&self) -> &Self::Target {
282 self.inner
283 }
284}
285
286impl DerefMut for BufferSlice<'_> {
287 fn deref_mut(&mut self) -> &mut Self::Target {
288 self.inner
289 }
290}
291
292pub struct Buffer {
300 pub(crate) inner: NonNull<u8>,
301 pub(crate) len: usize,
302 pub(crate) capacity: usize,
303 raw: Option<(sys::napi_ref, sys::napi_env)>,
304}
305
306impl Drop for Buffer {
307 fn drop(&mut self) {
308 if let Some((ref_, env)) = self.raw {
309 if ref_.is_null() {
310 return;
311 }
312 #[cfg(all(feature = "napi4", not(feature = "noop")))]
317 {
318 if CUSTOM_GC_TSFN_DESTROYED.load(std::sync::atomic::Ordering::SeqCst) {
319 return;
320 }
321 if !THREADS_CAN_ACCESS_ENV.with(|cell| cell.get()) {
323 let status = unsafe {
324 sys::napi_call_threadsafe_function(
325 CUSTOM_GC_TSFN.load(std::sync::atomic::Ordering::SeqCst),
326 ref_.cast(),
327 1,
328 )
329 };
330 assert!(
331 status == sys::Status::napi_ok || status == sys::Status::napi_closing,
332 "Call custom GC in Buffer::drop failed {}",
333 Status::from(status)
334 );
335 return;
336 }
337 }
338 let mut ref_count = 0;
339 check_status_or_throw!(
340 env,
341 unsafe { sys::napi_reference_unref(env, ref_, &mut ref_count) },
342 "Failed to unref Buffer reference in drop"
343 );
344 debug_assert!(
345 ref_count == 0,
346 "Buffer reference count in Buffer::drop is not zero"
347 );
348 check_status_or_throw!(
349 env,
350 unsafe { sys::napi_delete_reference(env, ref_) },
351 "Failed to delete Buffer reference in drop"
352 );
353 } else {
354 unsafe { Vec::from_raw_parts(self.inner.as_ptr(), self.len, self.capacity) };
355 }
356 }
357}
358
359unsafe impl Send for Buffer {}
362unsafe impl Sync for Buffer {}
363
364impl Default for Buffer {
365 fn default() -> Self {
366 Self::from(Vec::default())
367 }
368}
369
370impl From<Vec<u8>> for Buffer {
371 fn from(mut data: Vec<u8>) -> Self {
372 let inner_ptr = data.as_mut_ptr();
373 #[cfg(all(debug_assertions, not(windows), not(target_family = "wasm")))]
374 {
375 let is_existed = BUFFER_DATA.with(|buffer_data| {
376 let buffer = buffer_data.lock().expect("Unlock buffer data failed");
377 buffer.contains(&inner_ptr)
378 });
379 if is_existed {
380 panic!("Share the same data between different buffers is not allowed, see: https://github.com/nodejs/node/issues/32463#issuecomment-631974747");
381 }
382 }
383 let len = data.len();
384 let capacity = data.capacity();
385 mem::forget(data);
386 Buffer {
387 inner: unsafe { NonNull::new_unchecked(inner_ptr) },
391 len,
392 capacity,
393 raw: None,
394 }
395 }
396}
397
398impl From<Buffer> for Vec<u8> {
399 fn from(buf: Buffer) -> Self {
400 buf.as_ref().to_vec()
401 }
402}
403
404impl From<&[u8]> for Buffer {
405 fn from(inner: &[u8]) -> Self {
406 Buffer::from(inner.to_owned())
407 }
408}
409
410impl From<String> for Buffer {
411 fn from(inner: String) -> Self {
412 Buffer::from(inner.into_bytes())
413 }
414}
415
416impl AsRef<[u8]> for Buffer {
417 fn as_ref(&self) -> &[u8] {
418 unsafe { slice::from_raw_parts(self.inner.as_ptr(), self.len) }
420 }
421}
422
423impl AsMut<[u8]> for Buffer {
424 fn as_mut(&mut self) -> &mut [u8] {
425 unsafe { slice::from_raw_parts_mut(self.inner.as_ptr(), self.len) }
429 }
430}
431
432impl Deref for Buffer {
433 type Target = [u8];
434
435 fn deref(&self) -> &Self::Target {
436 self.as_ref()
437 }
438}
439
440impl DerefMut for Buffer {
441 fn deref_mut(&mut self) -> &mut Self::Target {
442 self.as_mut()
443 }
444}
445
446impl TypeName for Buffer {
447 fn type_name() -> &'static str {
448 "Vec<u8>"
449 }
450
451 fn value_type() -> ValueType {
452 ValueType::Object
453 }
454}
455
456impl FromNapiValue for Buffer {
457 unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
458 let mut buf = ptr::null_mut();
459 let mut len = 0;
460 let mut ref_ = ptr::null_mut();
461 check_status!(
462 unsafe { sys::napi_create_reference(env, napi_val, 1, &mut ref_) },
463 "Failed to create reference from Buffer"
464 )?;
465 check_status!(
466 unsafe { sys::napi_get_buffer_info(env, napi_val, &mut buf, &mut len as *mut usize) },
467 "Failed to get Buffer pointer and length"
468 )?;
469
470 let buf = NonNull::new(buf as *mut u8);
478 let inner = match buf {
479 Some(buf) if len != 0 => buf,
480 _ => NonNull::dangling(),
481 };
482
483 Ok(Self {
484 inner,
485 len,
486 capacity: len,
487 raw: Some((ref_, env)),
488 })
489 }
490}
491
492impl ToNapiValue for Buffer {
493 unsafe fn to_napi_value(env: sys::napi_env, mut val: Self) -> Result<sys::napi_value> {
494 if let Some((ref_, _)) = val.raw {
496 let mut buf = ptr::null_mut();
497 check_status!(
498 unsafe { sys::napi_get_reference_value(env, ref_, &mut buf) },
499 "Failed to get Buffer value from reference"
500 )?;
501
502 check_status!(
503 unsafe { sys::napi_delete_reference(env, ref_) },
504 "Failed to delete Buffer reference in Buffer::to_napi_value"
505 )?;
506 val.raw = Some((ptr::null_mut(), ptr::null_mut()));
507 return Ok(buf);
508 }
509 let len = val.len;
510 let mut ret = ptr::null_mut();
511 check_status!(
512 if len == 0 {
513 unsafe { sys::napi_create_buffer(env, len, ptr::null_mut(), &mut ret) }
517 } else {
518 let value_ptr = val.inner.as_ptr();
519 let val_box_ptr = Box::into_raw(Box::new(val));
520 let mut status = unsafe {
521 sys::napi_create_external_buffer(
522 env,
523 len,
524 value_ptr.cast(),
525 Some(drop_buffer),
526 val_box_ptr.cast(),
527 &mut ret,
528 )
529 };
530 if status == napi_sys::Status::napi_no_external_buffers_allowed {
531 let value = unsafe { Box::from_raw(val_box_ptr) };
532 status = unsafe {
533 sys::napi_create_buffer_copy(
534 env,
535 len,
536 value.inner.as_ptr() as *mut c_void,
537 ptr::null_mut(),
538 &mut ret,
539 )
540 };
541 }
542 status
543 },
544 "Failed to create napi buffer"
545 )?;
546
547 Ok(ret)
548 }
549}
550
551impl ValidateNapiValue for Buffer {
552 unsafe fn validate(env: sys::napi_env, napi_val: sys::napi_value) -> Result<sys::napi_value> {
553 let mut is_buffer = false;
554 check_status!(
555 unsafe { sys::napi_is_buffer(env, napi_val, &mut is_buffer) },
556 "Failed to validate napi buffer"
557 )?;
558 if !is_buffer {
559 return Err(Error::new(
560 Status::InvalidArg,
561 "Expected a Buffer value".to_owned(),
562 ));
563 }
564 Ok(ptr::null_mut())
565 }
566}