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