1use std::ffi::{c_void, CString};
2use std::marker::PhantomData;
3use std::mem;
4use std::ops::Deref;
5use std::ptr::{self, NonNull};
6
7#[cfg(all(feature = "napi4", not(feature = "noop")))]
8use crate::bindgen_prelude::{
9 current_custom_gc_handle, current_thread_owns_custom_gc, CustomGcHandle,
10};
11use crate::{
12 bindgen_prelude::{
13 FromNapiValue, JsObjectValue, JsValue, This, ToNapiValue, TypeName, ValidateNapiValue,
14 },
15 check_status, sys, Env, Error, Result, Status, Value, ValueType,
16};
17
18#[repr(i32)]
19#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
20#[non_exhaustive]
21pub enum TypedArrayType {
22 Int8 = 0,
23 Uint8,
24 Uint8Clamped,
25 Int16,
26 Uint16,
27 Int32,
28 Uint32,
29 Float32,
30 Float64,
31 #[cfg(feature = "napi6")]
32 BigInt64,
33 #[cfg(feature = "napi6")]
34 BigUint64,
35
36 Unknown = 1024,
38}
39
40impl AsRef<str> for TypedArrayType {
41 fn as_ref(&self) -> &str {
42 match self {
43 TypedArrayType::Int8 => "Int8",
44 TypedArrayType::Uint8 => "Uint8",
45 TypedArrayType::Uint8Clamped => "Uint8Clamped",
46 TypedArrayType::Int16 => "Int16",
47 TypedArrayType::Uint16 => "Uint16",
48 TypedArrayType::Int32 => "Int32",
49 TypedArrayType::Uint32 => "Uint32",
50 TypedArrayType::Float32 => "Float32",
51 TypedArrayType::Float64 => "Float64",
52 #[cfg(feature = "napi6")]
53 TypedArrayType::BigInt64 => "BigInt64",
54 #[cfg(feature = "napi6")]
55 TypedArrayType::BigUint64 => "BigUint64",
56 TypedArrayType::Unknown => "Unknown",
57 }
58 }
59}
60
61impl From<sys::napi_typedarray_type> for TypedArrayType {
62 fn from(value: sys::napi_typedarray_type) -> Self {
63 match value {
64 sys::TypedarrayType::int8_array => Self::Int8,
65 sys::TypedarrayType::uint8_array => Self::Uint8,
66 sys::TypedarrayType::uint8_clamped_array => Self::Uint8Clamped,
67 sys::TypedarrayType::int16_array => Self::Int16,
68 sys::TypedarrayType::uint16_array => Self::Uint16,
69 sys::TypedarrayType::int32_array => Self::Int32,
70 sys::TypedarrayType::uint32_array => Self::Uint32,
71 sys::TypedarrayType::float32_array => Self::Float32,
72 sys::TypedarrayType::float64_array => Self::Float64,
73 #[cfg(feature = "napi6")]
74 sys::TypedarrayType::bigint64_array => Self::BigInt64,
75 #[cfg(feature = "napi6")]
76 sys::TypedarrayType::biguint64_array => Self::BigUint64,
77 _ => Self::Unknown,
78 }
79 }
80}
81
82impl From<TypedArrayType> for sys::napi_typedarray_type {
83 fn from(value: TypedArrayType) -> sys::napi_typedarray_type {
84 value as i32
85 }
86}
87
88#[cfg(target_family = "wasm")]
89extern "C" {
90 fn emnapi_sync_memory(
91 env: crate::sys::napi_env,
92 js_to_wasm: bool,
93 arraybuffer_or_view: crate::sys::napi_value,
94 byte_offset: usize,
95 length: usize,
96 ) -> crate::sys::napi_status;
97}
98
99#[derive(Clone, Copy)]
100pub struct ArrayBuffer<'env> {
102 pub(crate) value: Value,
103 pub(crate) data: &'env [u8],
104}
105
106impl<'env> JsValue<'env> for ArrayBuffer<'env> {
107 fn value(&self) -> Value {
108 self.value
109 }
110}
111
112impl<'env> JsObjectValue<'env> for ArrayBuffer<'env> {}
113
114impl TypeName for ArrayBuffer<'_> {
115 fn type_name() -> &'static str {
116 "ArrayBuffer"
117 }
118
119 fn value_type() -> ValueType {
120 ValueType::Object
121 }
122}
123
124impl FromNapiValue for ArrayBuffer<'_> {
125 unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
126 let value = Value {
127 env,
128 value: napi_val,
129 value_type: ValueType::Object,
130 };
131 let mut data = ptr::null_mut();
132 let mut byte_length = 0;
133 check_status!(unsafe {
134 sys::napi_get_arraybuffer_info(env, napi_val, &mut data, &mut byte_length)
135 })?;
136 Ok(ArrayBuffer {
137 value,
138 data: if data.is_null() {
139 &[]
140 } else {
141 unsafe { std::slice::from_raw_parts(data as *const u8, byte_length) }
142 },
143 })
144 }
145}
146
147impl Deref for ArrayBuffer<'_> {
148 type Target = [u8];
149
150 fn deref(&self) -> &Self::Target {
151 self.data
152 }
153}
154
155impl<'env> ArrayBuffer<'env> {
156 pub fn from_data<D: Into<Vec<u8>>>(env: &Env, data: D) -> Result<Self> {
158 let mut buf = ptr::null_mut();
159 let mut data = data.into();
160 let mut inner_ptr = data.as_mut_ptr();
161 #[cfg(all(debug_assertions, not(windows), not(target_family = "wasm")))]
162 {
163 let is_existed = super::BUFFER_DATA.with(|buffer_data| {
164 let buffer = buffer_data.lock().expect("Unlock buffer data failed");
165 buffer.contains(&inner_ptr)
166 });
167 if is_existed {
168 panic!("Share the same data between different buffers is not allowed, see: https://github.com/nodejs/node/issues/32463#issuecomment-631974747");
169 }
170 }
171 let len = data.len();
172 let cap = data.capacity();
173 let finalize_hint = Box::into_raw(Box::new((len, cap)));
174 let mut status = unsafe {
175 sys::napi_create_external_arraybuffer(
176 env.0,
177 inner_ptr.cast(),
178 data.len(),
179 Some(finalize_slice::<u8>),
180 finalize_hint.cast(),
181 &mut buf,
182 )
183 };
184 if status == napi_sys::Status::napi_no_external_buffers_allowed {
185 unsafe {
186 let _ = Box::from_raw(finalize_hint);
187 }
188 let mut underlying_data = ptr::null_mut();
189 status =
190 unsafe { sys::napi_create_arraybuffer(env.0, data.len(), &mut underlying_data, &mut buf) };
191 check_status!(status, "Failed to create arraybuffer")?;
192 if len > 0 {
193 let underlying_slice: &mut [u8] =
194 unsafe { std::slice::from_raw_parts_mut(underlying_data.cast(), len) };
195 underlying_slice.copy_from_slice(data.as_slice());
196 }
197 inner_ptr = underlying_data.cast();
198 } else {
199 check_status!(status, "Failed to create arraybuffer")?;
200 mem::forget(data);
201 }
202 Ok(Self {
203 value: Value {
204 env: env.0,
205 value: buf,
206 value_type: ValueType::Object,
207 },
208 data: if len == 0 {
209 &[]
210 } else {
211 unsafe { std::slice::from_raw_parts(inner_ptr.cast(), len) }
212 },
213 })
214 }
215
216 pub unsafe fn from_external<T: 'env, F: FnOnce(Env, T)>(
236 env: &Env,
237 data: *mut u8,
238 len: usize,
239 finalize_hint: T,
240 finalize_callback: F,
241 ) -> Result<Self> {
242 if data.is_null() || std::ptr::eq(data, crate::EMPTY_VEC.as_ptr()) {
243 return Err(Error::new(
244 Status::InvalidArg,
245 "Borrowed data should not be null".to_owned(),
246 ));
247 }
248 #[cfg(all(debug_assertions, not(windows), not(target_family = "wasm")))]
249 {
250 let is_existed = super::BUFFER_DATA.with(|buffer_data| {
251 let buffer = buffer_data.lock().expect("Unlock buffer data failed");
252 buffer.contains(&data)
253 });
254 if is_existed {
255 panic!("Share the same data between different buffers is not allowed, see: https://github.com/nodejs/node/issues/32463#issuecomment-631974747");
256 }
257 }
258 let hint_ptr = Box::into_raw(Box::new((finalize_hint, finalize_callback)));
259 let mut arraybuffer_value = ptr::null_mut();
260 let mut status = unsafe {
261 sys::napi_create_external_arraybuffer(
262 env.0,
263 data.cast(),
264 len,
265 Some(crate::env::raw_finalize_with_custom_callback::<T, F>),
266 hint_ptr.cast(),
267 &mut arraybuffer_value,
268 )
269 };
270 let mut data_ptr = data;
273 if status == sys::Status::napi_no_external_buffers_allowed {
274 let (hint, finalize) = *Box::from_raw(hint_ptr);
275 let mut underlying_data = ptr::null_mut();
276 status = unsafe {
277 sys::napi_create_arraybuffer(env.0, len, &mut underlying_data, &mut arraybuffer_value)
278 };
279 if status == sys::Status::napi_ok && len > 0 {
281 unsafe { std::ptr::copy_nonoverlapping(data.cast(), underlying_data, len) };
282 }
283 finalize(*env, hint);
285 check_status!(status, "Failed to create arraybuffer from data")?;
286 data_ptr = underlying_data.cast();
287 } else {
288 check_status!(status, "Failed to create arraybuffer from data")?;
289 }
290
291 Ok(Self {
292 value: Value {
293 env: env.0,
294 value: arraybuffer_value,
295 value_type: ValueType::Object,
296 },
297 data: if len == 0 {
298 &[]
299 } else {
300 unsafe { std::slice::from_raw_parts(data_ptr, len) }
301 },
302 })
303 }
304
305 pub fn copy_from<D: AsRef<[u8]>>(env: &Env, data: D) -> Result<Self> {
307 let data = data.as_ref();
308 let len = data.len();
309 let mut arraybuffer_value = ptr::null_mut();
310 let mut underlying_data = ptr::null_mut();
311
312 check_status!(
313 unsafe {
314 sys::napi_create_arraybuffer(env.0, len, &mut underlying_data, &mut arraybuffer_value)
315 },
316 "Failed to create ArrayBuffer"
317 )?;
318
319 Ok(Self {
320 value: Value {
321 env: env.0,
322 value: arraybuffer_value,
323 value_type: ValueType::Object,
324 },
325 data: if len == 0 {
326 &[]
327 } else {
328 unsafe { std::slice::from_raw_parts(underlying_data.cast(), len) }
329 },
330 })
331 }
332
333 #[cfg(feature = "napi7")]
334 pub fn detach(self) -> Result<()> {
340 check_status!(unsafe { sys::napi_detach_arraybuffer(self.value.env, self.value.value) })
341 }
342
343 #[cfg(feature = "napi7")]
344 pub fn is_detached(&self) -> Result<bool> {
348 let mut is_detached = false;
349 check_status!(unsafe {
350 sys::napi_is_detached_arraybuffer(self.value.env, self.value.value, &mut is_detached)
351 })?;
352 Ok(is_detached)
353 }
354
355 pub unsafe fn as_mut(&mut self) -> &mut [u8] {
360 std::slice::from_raw_parts_mut(self.data.as_ptr() as *mut u8, self.data.len())
361 }
362}
363
364#[derive(Clone, Copy)]
365pub struct TypedArray<'env> {
367 pub(crate) value: Value,
368 pub typed_array_type: TypedArrayType,
369 pub arraybuffer: ArrayBuffer<'env>,
370 pub byte_offset: usize,
371}
372
373impl TypeName for TypedArray<'_> {
374 fn type_name() -> &'static str {
375 "TypedArray"
376 }
377
378 fn value_type() -> ValueType {
379 ValueType::Object
380 }
381}
382
383impl ValidateNapiValue for TypedArray<'_> {
384 unsafe fn validate(env: sys::napi_env, napi_val: sys::napi_value) -> Result<sys::napi_value> {
385 let mut is_typedarray = false;
386 check_status!(
387 unsafe { sys::napi_is_typedarray(env, napi_val, &mut is_typedarray) },
388 "Failed to validate TypedArray"
389 )?;
390 if !is_typedarray {
391 return Err(Error::new(
392 Status::InvalidArg,
393 "Value is not a TypedArray".to_owned(),
394 ));
395 }
396 Ok(ptr::null_mut())
397 }
398}
399
400impl<'env> JsValue<'env> for TypedArray<'env> {
401 fn value(&self) -> Value {
402 self.value
403 }
404}
405
406impl<'env> JsObjectValue<'env> for TypedArray<'env> {}
407
408impl FromNapiValue for TypedArray<'_> {
409 unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
410 let value = Value {
411 env,
412 value: napi_val,
413 value_type: ValueType::Object,
414 };
415 let mut typed_array_type = 0;
416 let mut data = ptr::null_mut();
417 let mut length = 0;
418 let mut arraybuffer = ptr::null_mut();
419 let mut byte_offset = 0;
420 check_status!(
421 unsafe {
422 sys::napi_get_typedarray_info(
423 env,
424 napi_val,
425 &mut typed_array_type,
426 &mut length,
427 &mut data,
428 &mut arraybuffer,
429 &mut byte_offset,
430 )
431 },
432 "Failed to get typedarray info"
433 )?;
434 Ok(Self {
435 value: Value {
436 env,
437 value: napi_val,
438 value_type: ValueType::Object,
439 },
440 typed_array_type: typed_array_type.into(),
441 byte_offset,
442 arraybuffer: ArrayBuffer {
443 value,
444 data: if data.is_null() {
445 &[]
446 } else {
447 unsafe { std::slice::from_raw_parts(data as *const u8, length) }
448 },
449 },
450 })
451 }
452}
453
454trait Finalizer {
455 type RustType;
456
457 fn finalizer_notify(&self) -> *mut dyn FnOnce(*mut Self::RustType, usize);
458}
459
460macro_rules! impl_typed_array {
461 ($name:ident, $rust_type:ident, $typed_array_type:expr) => {
462 pub struct $name {
463 data: *mut $rust_type,
464 length: usize,
465 capacity: usize,
466 #[allow(unused)]
467 byte_offset: usize,
468 raw: Option<(crate::sys::napi_ref, crate::sys::napi_env)>,
469 #[cfg(all(feature = "napi4", not(feature = "noop")))]
470 custom_gc_handle: Option<std::sync::Arc<CustomGcHandle>>,
471 finalizer_notify: *mut dyn FnOnce(*mut $rust_type, usize),
472 }
473
474 unsafe impl Send for $name {}
477 unsafe impl Sync for $name {}
478
479 impl Finalizer for $name {
480 type RustType = $rust_type;
481
482 fn finalizer_notify(&self) -> *mut dyn FnOnce(*mut Self::RustType, usize) {
483 self.finalizer_notify
484 }
485 }
486
487 impl Drop for $name {
488 fn drop(&mut self) {
489 if let Some((ref_, env)) = self.raw {
490 if ref_.is_null() || env.is_null() {
493 return;
494 }
495 #[cfg(all(feature = "napi4", not(feature = "noop")))]
496 {
497 if let Some(handle) = self.custom_gc_handle.as_ref() {
498 handle.with_read_aborted(|aborted| {
499 if aborted {
500 return;
503 }
504 if current_thread_owns_custom_gc(handle) {
505 let mut ref_count = 0;
509 crate::check_status_or_throw!(
510 env,
511 unsafe { sys::napi_reference_unref(env, ref_, &mut ref_count) },
512 "Failed to unref ArrayBuffer reference in drop"
513 );
514 debug_assert!(
515 ref_count == 0,
516 "ArrayBuffer reference count in ArrayBuffer::drop is not zero"
517 );
518 crate::check_status_or_throw!(
519 env,
520 unsafe { sys::napi_delete_reference(env, ref_) },
521 "Failed to delete ArrayBuffer reference in drop"
522 );
523 } else {
524 let status =
526 unsafe { sys::napi_call_threadsafe_function(handle.get_raw(), ref_.cast(), 1) };
527 assert!(
528 status == sys::Status::napi_ok || status == sys::Status::napi_closing,
529 "Call custom GC in ArrayBuffer::drop failed {}",
530 Status::from(status)
531 );
532 }
533 });
534 return;
535 }
536 }
541 let mut ref_count = 0;
542 crate::check_status_or_throw!(
543 env,
544 unsafe { sys::napi_reference_unref(env, ref_, &mut ref_count) },
545 "Failed to unref ArrayBuffer reference in drop"
546 );
547 debug_assert!(
548 ref_count == 0,
549 "ArrayBuffer reference count in ArrayBuffer::drop is not zero"
550 );
551 crate::check_status_or_throw!(
552 env,
553 unsafe { sys::napi_delete_reference(env, ref_) },
554 "Failed to delete ArrayBuffer reference in drop"
555 );
556 return;
557 }
558 if !self.finalizer_notify().is_null() {
560 let finalizer = unsafe { Box::from_raw(self.finalizer_notify) };
561 (finalizer)(self.data, self.length);
562 return;
563 }
564 if !self.data.is_null() {
565 unsafe { Vec::from_raw_parts(self.data, self.length, self.capacity) };
566 }
567 }
568 }
569
570 impl $name {
571 #[cfg(target_family = "wasm")]
572 pub fn sync(&mut self, env: &crate::Env) {
573 if let Some((reference, _)) = self.raw {
574 let mut value = ptr::null_mut();
575 let mut array_buffer = ptr::null_mut();
576 crate::check_status_or_throw!(
577 env.raw(),
578 unsafe { crate::sys::napi_get_reference_value(env.raw(), reference, &mut value) },
579 "Failed to get reference value from TypedArray while syncing"
580 );
581 crate::check_status_or_throw!(
582 env.raw(),
583 unsafe {
584 crate::sys::napi_get_typedarray_info(
585 env.raw(),
586 value,
587 &mut ($typed_array_type as i32) as *mut i32,
588 &mut self.length as *mut usize,
589 ptr::null_mut(),
590 &mut array_buffer,
591 &mut self.byte_offset as *mut usize,
592 )
593 },
594 "Failed to get ArrayBuffer under the TypedArray while syncing"
595 );
596 crate::check_status_or_throw!(
597 env.raw(),
598 unsafe {
599 emnapi_sync_memory(
600 env.raw(),
601 false,
602 array_buffer,
603 self.byte_offset,
604 self.length,
605 )
606 },
607 "Failed to sync memory"
608 );
609 } else {
610 return;
611 }
612 }
613
614 pub fn new(mut data: Vec<$rust_type>) -> Self {
615 data.shrink_to_fit();
616 let ret = $name {
617 data: data.as_mut_ptr(),
618 length: data.len(),
619 capacity: data.capacity(),
620 byte_offset: 0,
621 raw: None,
622 #[cfg(all(feature = "napi4", not(feature = "noop")))]
623 custom_gc_handle: None,
624 finalizer_notify: ptr::null_mut::<fn(*mut $rust_type, usize)>(),
625 };
626 mem::forget(data);
627 ret
628 }
629
630 pub fn with_data_copied<D>(data: D) -> Self
631 where
632 D: AsRef<[$rust_type]>,
633 {
634 let mut data_copied = data.as_ref().to_vec();
635 let ret = $name {
636 data: data_copied.as_mut_ptr(),
637 length: data.as_ref().len(),
638 capacity: data_copied.capacity(),
639 finalizer_notify: ptr::null_mut::<fn(*mut $rust_type, usize)>(),
640 raw: None,
641 #[cfg(all(feature = "napi4", not(feature = "noop")))]
642 custom_gc_handle: None,
643 byte_offset: 0,
644 };
645 mem::forget(data_copied);
646 ret
647 }
648
649 pub unsafe fn with_external_data<F>(data: *mut $rust_type, length: usize, notify: F) -> Self
653 where
654 F: 'static + FnOnce(*mut $rust_type, usize),
655 {
656 $name {
657 data,
658 length,
659 capacity: length,
660 finalizer_notify: Box::into_raw(Box::new(notify)),
661 raw: None,
662 #[cfg(all(feature = "napi4", not(feature = "noop")))]
663 custom_gc_handle: None,
664 byte_offset: 0,
665 }
666 }
667
668 #[allow(clippy::should_implement_trait)]
669 pub unsafe fn as_mut(&mut self) -> &mut [$rust_type] {
674 if self.data.is_null() {
675 return &mut [];
676 }
677
678 unsafe { std::slice::from_raw_parts_mut(self.data, self.length) }
679 }
680 }
681
682 impl Deref for $name {
683 type Target = [$rust_type];
684
685 fn deref(&self) -> &Self::Target {
686 self.as_ref()
687 }
688 }
689
690 impl AsRef<[$rust_type]> for $name {
691 fn as_ref(&self) -> &[$rust_type] {
692 if self.data.is_null() {
693 return &[];
694 }
695
696 unsafe { std::slice::from_raw_parts(self.data, self.length) }
697 }
698 }
699
700 impl TypeName for $name {
701 fn type_name() -> &'static str {
702 concat!("TypedArray<", stringify!($rust_type), ">")
703 }
704
705 fn value_type() -> crate::ValueType {
706 crate::ValueType::Object
707 }
708 }
709
710 impl ValidateNapiValue for $name {
711 unsafe fn validate(
712 env: sys::napi_env,
713 napi_val: sys::napi_value,
714 ) -> Result<crate::sys::napi_value> {
715 let mut is_typed_array = false;
716 check_status!(
717 unsafe { sys::napi_is_typedarray(env, napi_val, &mut is_typed_array) },
718 "Failed to check if value is typed array"
719 )?;
720 if !is_typed_array {
721 return Err(Error::new(
722 Status::InvalidArg,
723 "Expected a TypedArray value".to_owned(),
724 ));
725 }
726 Ok(ptr::null_mut())
727 }
728 }
729
730 impl FromNapiValue for $name {
731 unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
732 let mut typed_array_type = 0;
733 let mut length = 0;
734 let mut data = ptr::null_mut();
735 let mut array_buffer = ptr::null_mut();
736 let mut byte_offset = 0;
737 let mut ref_ = ptr::null_mut();
738 check_status!(
739 unsafe { sys::napi_create_reference(env, napi_val, 1, &mut ref_) },
740 "Failed to create reference from TypedArray"
741 )?;
742 check_status!(
743 unsafe {
744 sys::napi_get_typedarray_info(
745 env,
746 napi_val,
747 &mut typed_array_type,
748 &mut length,
749 &mut data,
750 &mut array_buffer,
751 &mut byte_offset,
752 )
753 },
754 "Get TypedArray info failed"
755 )?;
756 if typed_array_type != $typed_array_type as i32 {
757 return Err(Error::new(
758 Status::InvalidArg,
759 format!(
760 "Expected {}, got {}Array",
761 stringify!($name),
762 TypedArrayType::from(typed_array_type).as_ref()
763 ),
764 ));
765 }
766 Ok($name {
767 data: data.cast(),
768 length,
769 capacity: length,
770 byte_offset,
771 raw: Some((ref_, env)),
772 #[cfg(all(feature = "napi4", not(feature = "noop")))]
773 custom_gc_handle: current_custom_gc_handle(),
774 finalizer_notify: ptr::null_mut::<fn(*mut $rust_type, usize)>(),
775 })
776 }
777 }
778
779 impl ToNapiValue for $name {
780 unsafe fn to_napi_value(env: sys::napi_env, mut val: Self) -> Result<sys::napi_value> {
781 if let Some((ref_, _)) = val.raw {
782 let mut napi_value = std::ptr::null_mut();
783 check_status!(
784 unsafe { sys::napi_get_reference_value(env, ref_, &mut napi_value) },
785 "Failed to get reference from ArrayBuffer"
786 )?;
787 check_status!(
788 unsafe { sys::napi_delete_reference(env, ref_) },
789 "Failed to delete reference in ArrayBuffer::to_napi_value"
790 )?;
791 val.raw = Some((ptr::null_mut(), ptr::null_mut()));
792 return Ok(napi_value);
793 }
794 let mut arraybuffer_value = ptr::null_mut();
795 let ratio = mem::size_of::<$rust_type>();
796 let val_length = val.length;
797 let length = val_length * ratio;
798 let val_data = val.data;
799 if length == 0 {
800 check_status!(
804 unsafe {
805 sys::napi_create_arraybuffer(env, length, ptr::null_mut(), &mut arraybuffer_value)
806 },
807 "Create external arraybuffer failed"
808 )?;
809 } else {
810 let hint_ptr = Box::into_raw(Box::new(val));
811 let mut status = unsafe {
812 sys::napi_create_external_arraybuffer(
813 env,
814 val_data.cast(),
815 length,
816 Some(finalizer::<$rust_type, $name>),
817 hint_ptr.cast(),
818 &mut arraybuffer_value,
819 )
820 };
821 if status == napi_sys::Status::napi_no_external_buffers_allowed {
822 let hint = unsafe { Box::from_raw(hint_ptr) };
823 let mut underlying_data = ptr::null_mut();
824 status = unsafe {
825 sys::napi_create_arraybuffer(
826 env,
827 length,
828 &mut underlying_data,
829 &mut arraybuffer_value,
830 )
831 };
832 check_status!(status, "Create external arraybuffer failed")?;
833 if length > 0 {
834 unsafe { std::ptr::copy_nonoverlapping(hint.data.cast(), underlying_data, length) };
835 }
836 } else {
837 check_status!(status, "Create external arraybuffer failed")?;
838 }
839 }
840 let mut napi_val = ptr::null_mut();
841 check_status!(
842 unsafe {
843 sys::napi_create_typedarray(
844 env,
845 $typed_array_type as i32,
846 val_length,
847 arraybuffer_value,
848 0,
849 &mut napi_val,
850 )
851 },
852 "Create TypedArray failed"
853 )?;
854 Ok(napi_val)
855 }
856 }
857
858 impl ToNapiValue for &mut $name {
859 unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
860 if let Some((ref_, _)) = val.raw {
861 let mut napi_value = std::ptr::null_mut();
862 check_status!(
863 unsafe { sys::napi_get_reference_value(env, ref_, &mut napi_value) },
864 "Failed to get reference from ArrayBuffer"
865 )?;
866 return Ok(napi_value);
867 }
868 let mut arraybuffer_value = ptr::null_mut();
869 let ratio = mem::size_of::<$rust_type>();
870 let val_length = val.length;
871 let length = val_length * ratio;
872 let val_data = val.data;
873 let mut copied_val = None;
874 if length == 0 {
875 check_status!(
879 unsafe {
880 sys::napi_create_arraybuffer(env, length, ptr::null_mut(), &mut arraybuffer_value)
881 },
882 "Create external arraybuffer failed"
883 )?;
884 } else {
885 let val_copy = $name {
888 data: val.data,
889 length: val.length,
890 capacity: val.capacity,
891 byte_offset: val.byte_offset,
892 raw: None,
893 #[cfg(all(feature = "napi4", not(feature = "noop")))]
894 custom_gc_handle: None,
895 finalizer_notify: val.finalizer_notify,
896 };
897 let hint_ref: &mut $name = Box::leak(Box::new(val_copy));
898 let hint_ptr = hint_ref as *mut $name;
899 copied_val = Some(hint_ref);
900 let mut status = unsafe {
901 sys::napi_create_external_arraybuffer(
902 env,
903 val_data.cast(),
904 length,
905 Some(finalizer::<$rust_type, $name>),
906 hint_ptr.cast(),
907 &mut arraybuffer_value,
908 )
909 };
910 if status == napi_sys::Status::napi_no_external_buffers_allowed {
911 let hint = unsafe { Box::from_raw(hint_ptr) };
912 copied_val = None;
914 val.data = ptr::null_mut();
920 val.length = 0;
921 val.capacity = 0;
922 val.finalizer_notify = ptr::null_mut::<fn(*mut $rust_type, usize)>();
923 let mut underlying_data = ptr::null_mut();
924 status = unsafe {
925 sys::napi_create_arraybuffer(
926 env,
927 length,
928 &mut underlying_data,
929 &mut arraybuffer_value,
930 )
931 };
932 check_status!(status, "Create external arraybuffer failed")?;
933 if length > 0 {
934 unsafe { std::ptr::copy_nonoverlapping(hint.data.cast(), underlying_data, length) };
935 }
936 } else {
937 check_status!(status, "Create external arraybuffer failed")?;
938 }
939 }
940 let mut napi_val = ptr::null_mut();
941 check_status!(
942 unsafe {
943 sys::napi_create_typedarray(
944 env,
945 $typed_array_type as i32,
946 val_length,
947 arraybuffer_value,
948 0,
949 &mut napi_val,
950 )
951 },
952 "Create TypedArray failed"
953 )?;
954 let mut ref_ = ptr::null_mut();
955 check_status!(
956 unsafe { sys::napi_create_reference(env, napi_val, 1, &mut ref_) },
957 "Failed to delete reference in ArrayBuffer::to_napi_value"
958 )?;
959 val.raw = Some((ref_, env));
960 #[cfg(all(feature = "napi4", not(feature = "noop")))]
961 {
962 val.custom_gc_handle = current_custom_gc_handle();
963 }
964 if let Some(copied_val) = copied_val {
965 val.finalizer_notify = ptr::null_mut::<fn(*mut $rust_type, usize)>();
966 val.data = ptr::null_mut();
967 val.length = 0;
968 val.capacity = 0;
969 copied_val.raw = Some((ref_, ptr::null_mut()));
970 }
971 Ok(napi_val)
972 }
973 }
974 };
975}
976
977macro_rules! impl_from_slice {
978 ($name:ident, $slice_type:ident, $rust_type:ident, $typed_array_type:expr) => {
979 #[derive(Clone, Copy)]
980 pub struct $slice_type<'env> {
981 pub(crate) inner: NonNull<$rust_type>,
982 pub(crate) length: usize,
983 raw_value: sys::napi_value,
984 env: sys::napi_env,
985 _marker: PhantomData<&'env ()>,
986 }
987
988 impl <'env> $slice_type<'env> {
989 #[doc = " Create a new `"]
990 #[doc = stringify!($slice_type)]
991 #[doc = "` from a `Vec<"]
992 #[doc = stringify!($rust_type)]
993 #[doc = ">`."]
994 pub fn from_data<D: Into<Vec<$rust_type>>>(env: &Env, data: D) -> Result<Self> {
995 let mut buf = ptr::null_mut();
996 let mut data = data.into();
997 let mut inner_ptr = data.as_mut_ptr();
998 #[cfg(all(debug_assertions, not(windows), not(target_family = "wasm")))]
999 {
1000 let is_existed = super::BUFFER_DATA.with(|buffer_data| {
1001 let buffer = buffer_data.lock().expect("Unlock buffer data failed");
1002 buffer.contains(&inner_ptr.cast())
1003 });
1004 if is_existed {
1005 panic!("Share the same data between different buffers is not allowed, see: https://github.com/nodejs/node/issues/32463#issuecomment-631974747");
1006 }
1007 }
1008 let len = data.len();
1009 let array_buffer_len = len * mem::size_of::<$rust_type>();
1010 let cap = data.capacity();
1011 let finalize_hint = Box::into_raw(Box::new((len, cap)));
1012 let mut status = unsafe {
1013 sys::napi_create_external_arraybuffer(
1014 env.0,
1015 inner_ptr.cast(),
1016 array_buffer_len,
1017 Some(finalize_slice::<$rust_type>),
1018 finalize_hint.cast(),
1019 &mut buf,
1020 )
1021 };
1022 if status == napi_sys::Status::napi_no_external_buffers_allowed {
1023 unsafe {
1024 let _ = Box::from_raw(finalize_hint);
1025 }
1026 let mut underlying_data = ptr::null_mut();
1027 status = unsafe {
1028 sys::napi_create_arraybuffer(
1029 env.0,
1030 array_buffer_len,
1031 &mut underlying_data,
1032 &mut buf,
1033 )
1034 };
1035 check_status!(status, "Failed to create buffer slice from data")?;
1036 if array_buffer_len > 0 {
1037 let underlying_slice: &mut [u8] =
1038 unsafe { std::slice::from_raw_parts_mut(underlying_data.cast(), array_buffer_len) };
1039 underlying_slice.copy_from_slice(unsafe { core::slice::from_raw_parts(inner_ptr.cast(), array_buffer_len) });
1040 }
1041 inner_ptr = underlying_data.cast();
1042 } else {
1043 check_status!(status, "Failed to create buffer slice from data")?;
1044 mem::forget(data);
1045 }
1046
1047 let mut napi_val = ptr::null_mut();
1048 check_status!(
1049 unsafe {
1050 sys::napi_create_typedarray(
1051 env.0,
1052 $typed_array_type as i32,
1053 len,
1054 buf,
1055 0,
1056 &mut napi_val,
1057 )
1058 },
1059 "Create TypedArray failed"
1060 )?;
1061
1062 Ok(Self {
1063 inner: if len == 0 {
1064 NonNull::dangling()
1065 } else {
1066 unsafe { NonNull::new_unchecked(inner_ptr.cast()) }
1067 },
1068 length: len,
1069 raw_value: napi_val,
1070 env: env.0,
1071 _marker: PhantomData,
1072 })
1073 }
1074
1075 #[doc = "Mostly the same with `from_data`"]
1076 #[doc = ""]
1077 #[doc = "Provided `finalize_callback` will be called when `"]
1078 #[doc = stringify!($slice_type)]
1079 #[doc = "` got dropped."]
1080 #[doc = "You can pass in `noop_finalize` if you have nothing to do in finalize phase."]
1081 #[doc = ""]
1082 #[doc = "## Safety"]
1083 #[doc = ""]
1084 #[doc = "The caller must ensure that:"]
1085 #[doc = "- The data pointer is valid for the lifetime of the buffer and points to a memory region of at least `len` elements"]
1086 #[doc = "- The finalize callback properly cleans up the data"]
1087 #[doc = ""]
1088 #[doc = "### Notes"]
1089 #[doc = ""]
1090 #[doc = "JavaScript may mutate the data passed in to this buffer when writing the buffer."]
1091 #[doc = "However, some JavaScript runtimes do not support external buffers (notably electron!)"]
1092 #[doc = "in which case modifications may be lost."]
1093 #[doc = ""]
1094 #[doc = "If you need to support these runtimes, you should create a buffer by other means and then"]
1095 #[doc = "later copy the data back out."]
1096 pub unsafe fn from_external<T: 'env, F: FnOnce(Env, T)>(
1097 env: &Env,
1098 data: *mut $rust_type,
1099 data_len: usize,
1100 finalize_hint: T,
1101 finalize_callback: F,
1102 ) -> Result<Self> {
1103 if data.is_null() || data as *const u8 == crate::EMPTY_VEC.as_ptr() {
1104 return Err(Error::new(
1105 Status::InvalidArg,
1106 "Borrowed data should not be null".to_owned(),
1107 ));
1108 }
1109 #[cfg(all(debug_assertions, not(windows), not(target_family = "wasm")))]
1110 {
1111 let is_existed = super::BUFFER_DATA.with(|buffer_data| {
1112 let buffer = buffer_data.lock().expect("Unlock buffer data failed");
1113 buffer.contains(&data.cast())
1114 });
1115 if is_existed {
1116 panic!("Share the same data between different buffers is not allowed, see: https://github.com/nodejs/node/issues/32463#issuecomment-631974747");
1117 }
1118 }
1119 let hint_ptr = Box::into_raw(Box::new((finalize_hint, finalize_callback)));
1120 let mut arraybuffer_value = ptr::null_mut();
1121 let array_buffer_len = data_len * mem::size_of::<$rust_type>();
1122 let mut status = unsafe {
1123 sys::napi_create_external_arraybuffer(
1124 env.0,
1125 data.cast(),
1126 array_buffer_len,
1127 Some(crate::env::raw_finalize_with_custom_callback::<T, F>),
1128 hint_ptr.cast(),
1129 &mut arraybuffer_value,
1130 )
1131 };
1132 let mut inner_ptr: *mut $rust_type = data;
1135 if status == sys::Status::napi_no_external_buffers_allowed {
1136 let (hint, finalize) = *Box::from_raw(hint_ptr);
1137 let mut underlying_data = ptr::null_mut();
1138 status = unsafe {
1139 sys::napi_create_arraybuffer(
1140 env.0,
1141 array_buffer_len,
1142 &mut underlying_data,
1143 &mut arraybuffer_value,
1144 )
1145 };
1146 if status == sys::Status::napi_ok && array_buffer_len > 0 {
1148 let underlying_slice: &mut [u8] =
1149 unsafe { std::slice::from_raw_parts_mut(underlying_data.cast(), array_buffer_len) };
1150 underlying_slice.copy_from_slice(unsafe { std::slice::from_raw_parts(data.cast(), array_buffer_len) });
1151 }
1152 finalize(*env, hint);
1154 check_status!(status, "Failed to create arraybuffer from data")?;
1155 inner_ptr = underlying_data.cast();
1156 } else {
1157 check_status!(status, "Failed to create arraybuffer from data")?;
1158 }
1159
1160 let mut napi_val = ptr::null_mut();
1161 check_status!(
1162 unsafe {
1163 sys::napi_create_typedarray(
1164 env.0,
1165 $typed_array_type as i32,
1166 data_len,
1167 arraybuffer_value,
1168 0,
1169 &mut napi_val,
1170 )
1171 },
1172 "Create TypedArray failed"
1173 )?;
1174
1175 Ok(Self {
1176 inner: if data_len == 0 {
1177 NonNull::dangling()
1178 } else {
1179 unsafe { NonNull::new_unchecked(inner_ptr) }
1180 },
1181 length: data_len,
1182 raw_value: napi_val,
1183 env: env.0,
1184 _marker: PhantomData,
1185 })
1186 }
1187
1188 #[doc = "Copy data from a `&["]
1189 #[doc = stringify!($rust_type)]
1190 #[doc = "]` and create a `"]
1191 #[doc = stringify!($slice_type)]
1192 #[doc = "` from it."]
1193 pub fn copy_from<D: AsRef<[$rust_type]>>(env: &Env, data: D) -> Result<Self> {
1194 let data = data.as_ref();
1195 let len = data.len();
1196 let mut arraybuffer_value = ptr::null_mut();
1197 let mut underlying_data = ptr::null_mut();
1198
1199 check_status!(
1200 unsafe {
1201 sys::napi_create_arraybuffer(
1202 env.0,
1203 len,
1204 &mut underlying_data,
1205 &mut arraybuffer_value,
1206 )
1207 },
1208 "Failed to create ArrayBuffer"
1209 )?;
1210
1211 let mut napi_val = ptr::null_mut();
1212 check_status!(
1213 unsafe {
1214 sys::napi_create_typedarray(
1215 env.0,
1216 $typed_array_type as i32,
1217 len,
1218 arraybuffer_value,
1219 0,
1220 &mut napi_val,
1221 )
1222 },
1223 "Create TypedArray failed"
1224 )?;
1225
1226 Ok(Self {
1227 inner: if len == 0 {
1228 NonNull::dangling()
1229 } else {
1230 unsafe { NonNull::new_unchecked(underlying_data.cast()) }
1231 },
1232 length: len,
1233 raw_value: napi_val,
1234 env: env.0,
1235 _marker: PhantomData,
1236 })
1237 }
1238
1239 pub fn from_arraybuffer(arraybuffer: &ArrayBuffer<'env>, byte_offset: usize, length: usize) -> Result<$slice_type<'env>> {
1241 let env = arraybuffer.value.env;
1242 let mut typed_array = ptr::null_mut();
1243 check_status!(unsafe {
1244 sys::napi_create_typedarray(env, $typed_array_type.into(), length, arraybuffer.value().value, byte_offset, &mut typed_array)
1245 }, "Failed to create TypedArray from ArrayBuffer")?;
1246
1247 unsafe { FromNapiValue::from_napi_value(env, typed_array) }
1248 }
1249
1250 pub fn assign_to_this<'a, U>(&self, this: This<'a, U>, name: &str) -> Result<$slice_type<'a>>
1252 where
1253 U: FromNapiValue + JsObjectValue<'a>,
1254 {
1255 let name = CString::new(name)?;
1256 check_status!(
1257 unsafe { sys::napi_set_named_property(self.env, this.object.raw(), name.as_ptr(), self.raw_value) },
1258 "Failed to assign {} to this",
1259 $slice_type::type_name()
1260 )?;
1261 Ok($slice_type {
1262 env: self.env,
1263 raw_value: self.raw_value,
1264 inner: self.inner,
1265 length: self.length,
1266 _marker: PhantomData,
1267 })
1268 }
1269
1270 #[allow(clippy::should_implement_trait)]
1271 pub unsafe fn as_mut(&mut self) -> &mut [$rust_type] {
1276 unsafe { core::slice::from_raw_parts_mut(self.inner.as_ptr(), self.length) }
1277 }
1278
1279 #[doc = "Convert a `"]
1280 #[doc = stringify!($slice_type)]
1281 #[doc = "` to a `"]
1282 #[doc = stringify!($name)]
1283 #[doc = "`."]
1284 #[doc = ""]
1285 #[doc = "This will perform a `napi_create_reference` internally."]
1286 pub fn into_typed_array(self, env: &Env) -> Result<$name> {
1287 unsafe { $name::from_napi_value(env.0, self.raw_value) }
1288 }
1289 }
1290
1291 impl<'env> JsValue<'env> for $slice_type<'env> {
1292 fn value(&self) -> Value {
1293 Value {
1294 env: self.env,
1295 value: self.raw_value,
1296 value_type: ValueType::Object,
1297 }
1298 }
1299 }
1300
1301 impl<'env> JsObjectValue<'env> for $slice_type<'env> { }
1302
1303 impl ToNapiValue for &$slice_type<'_> {
1304 unsafe fn to_napi_value(_: sys::napi_env, val: Self) -> Result<sys::napi_value> {
1305 Ok(val.raw_value)
1306 }
1307 }
1308
1309 impl ToNapiValue for &mut $slice_type<'_> {
1310 unsafe fn to_napi_value(_: sys::napi_env, val: Self) -> Result<sys::napi_value> {
1311 Ok(val.raw_value)
1312 }
1313 }
1314
1315 impl FromNapiValue for $slice_type<'_> {
1316 unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
1317 let mut typed_array_type = 0;
1318 let mut length = 0;
1319 let mut data = ptr::null_mut();
1320 let mut array_buffer = ptr::null_mut();
1321 let mut byte_offset = 0;
1322 check_status!(
1323 unsafe {
1324 sys::napi_get_typedarray_info(
1325 env,
1326 napi_val,
1327 &mut typed_array_type,
1328 &mut length,
1329 &mut data,
1330 &mut array_buffer,
1331 &mut byte_offset,
1332 )
1333 },
1334 "Get TypedArray info failed"
1335 )?;
1336 if typed_array_type != $typed_array_type as i32 {
1337 return Err(Error::new(
1338 Status::InvalidArg,
1339 format!("Expected $name, got {}", typed_array_type),
1340 ));
1341 }
1342 Ok(Self {
1350 inner: if length == 0 {
1351 ptr::NonNull::dangling()
1352 } else {
1353 ptr::NonNull::new_unchecked(data.cast())
1354 },
1355 length,
1356 raw_value: napi_val,
1357 env,
1358 _marker: PhantomData,
1359 })
1360 }
1361 }
1362
1363 impl TypeName for $slice_type<'_> {
1364 fn type_name() -> &'static str {
1365 concat!("TypedArray<", stringify!($rust_type), ">")
1366 }
1367
1368 fn value_type() -> crate::ValueType {
1369 crate::ValueType::Object
1370 }
1371 }
1372
1373 impl ValidateNapiValue for $slice_type<'_> {
1374 unsafe fn validate(env: sys::napi_env, napi_val: sys::napi_value) -> Result<sys::napi_value> {
1375 let mut is_typed_array = false;
1376 check_status!(
1377 unsafe { sys::napi_is_typedarray(env, napi_val, &mut is_typed_array) },
1378 "Failed to validate napi typed array"
1379 )?;
1380 if !is_typed_array {
1381 return Err(Error::new(
1382 Status::InvalidArg,
1383 "Expected a TypedArray value".to_owned(),
1384 ));
1385 }
1386 Ok(ptr::null_mut())
1387 }
1388 }
1389
1390 impl AsRef<[$rust_type]> for $slice_type<'_> {
1391 fn as_ref(&self) -> &[$rust_type] {
1392 unsafe { core::slice::from_raw_parts(self.inner.as_ptr(), self.length) }
1393 }
1394 }
1395
1396 impl Deref for $slice_type<'_> {
1397 type Target = [$rust_type];
1398
1399 fn deref(&self) -> &Self::Target {
1400 self.as_ref()
1401 }
1402 }
1403
1404 impl FromNapiValue for &mut [$rust_type] {
1405 unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
1406 let mut typed_array_type = 0;
1407 let mut length = 0;
1408 let mut data = ptr::null_mut();
1409 let mut array_buffer = ptr::null_mut();
1410 let mut byte_offset = 0;
1411 check_status!(
1412 unsafe {
1413 sys::napi_get_typedarray_info(
1414 env,
1415 napi_val,
1416 &mut typed_array_type,
1417 &mut length,
1418 &mut data,
1419 &mut array_buffer,
1420 &mut byte_offset,
1421 )
1422 },
1423 "Get TypedArray info failed"
1424 )?;
1425 if typed_array_type != $typed_array_type as i32 {
1426 return Err(Error::new(
1427 Status::InvalidArg,
1428 format!("Expected $name, got {}", typed_array_type),
1429 ));
1430 }
1431 Ok(if length == 0 {
1432 &mut []
1433 } else {
1434 unsafe { core::slice::from_raw_parts_mut(data as *mut $rust_type, length) }
1435 })
1436 }
1437 }
1438
1439 impl FromNapiValue for &[$rust_type] {
1440 unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
1441 let mut typed_array_type = 0;
1442 let mut length = 0;
1443 let mut data = ptr::null_mut();
1444 let mut array_buffer = ptr::null_mut();
1445 let mut byte_offset = 0;
1446 check_status!(
1447 unsafe {
1448 sys::napi_get_typedarray_info(
1449 env,
1450 napi_val,
1451 &mut typed_array_type,
1452 &mut length,
1453 &mut data,
1454 &mut array_buffer,
1455 &mut byte_offset,
1456 )
1457 },
1458 "Get TypedArray info failed"
1459 )?;
1460 if typed_array_type != $typed_array_type as i32 {
1461 return Err(Error::new(
1462 Status::InvalidArg,
1463 format!("Expected $name, got {}", typed_array_type),
1464 ));
1465 }
1466 Ok(if length == 0 {
1467 &[]
1468 } else {
1469 unsafe { core::slice::from_raw_parts_mut(data as *mut $rust_type, length) }
1470 })
1471 }
1472 }
1473
1474 impl TypeName for &mut [$rust_type] {
1475 fn type_name() -> &'static str {
1476 concat!("TypedArray<", stringify!($rust_type), ">")
1477 }
1478
1479 fn value_type() -> crate::ValueType {
1480 crate::ValueType::Object
1481 }
1482 }
1483
1484 impl TypeName for &[$rust_type] {
1485 fn type_name() -> &'static str {
1486 concat!("TypedArray<", stringify!($rust_type), ">")
1487 }
1488
1489 fn value_type() -> crate::ValueType {
1490 crate::ValueType::Object
1491 }
1492 }
1493
1494 impl ValidateNapiValue for &[$rust_type] {
1495 unsafe fn validate(env: sys::napi_env, napi_val: sys::napi_value) -> Result<sys::napi_value> {
1496 let mut is_typed_array = false;
1497 check_status!(
1498 unsafe { sys::napi_is_typedarray(env, napi_val, &mut is_typed_array) },
1499 "Failed to validate napi typed array"
1500 )?;
1501 if !is_typed_array {
1502 return Err(Error::new(
1503 Status::InvalidArg,
1504 "Expected a TypedArray value".to_owned(),
1505 ));
1506 }
1507 Ok(ptr::null_mut())
1508 }
1509 }
1510
1511 impl ValidateNapiValue for &mut [$rust_type] {
1512 unsafe fn validate(env: sys::napi_env, napi_val: sys::napi_value) -> Result<sys::napi_value> {
1513 let mut is_typed_array = false;
1514 check_status!(
1515 unsafe { sys::napi_is_typedarray(env, napi_val, &mut is_typed_array) },
1516 "Failed to validate napi typed array"
1517 )?;
1518 if !is_typed_array {
1519 return Err(Error::new(
1520 Status::InvalidArg,
1521 "Expected a TypedArray value".to_owned(),
1522 ));
1523 }
1524 Ok(ptr::null_mut())
1525 }
1526 }
1527 };
1528}
1529
1530unsafe extern "C" fn finalizer<Data, T: Finalizer<RustType = Data> + AsRef<[Data]>>(
1531 _env: sys::napi_env,
1532 _finalize_data: *mut c_void,
1533 finalize_hint: *mut c_void,
1534) {
1535 let data = unsafe { *Box::from_raw(finalize_hint as *mut T) };
1536 drop(data);
1537}
1538
1539unsafe extern "C" fn finalize_slice<Data>(
1540 _env: sys::napi_env,
1541 finalize_data: *mut c_void,
1542 finalize_hint: *mut c_void,
1543) {
1544 let (length, capacity): (usize, usize) =
1545 *unsafe { Box::from_raw(finalize_hint as *mut (usize, usize)) };
1546 if finalize_data.is_null() {
1547 return;
1548 }
1549 unsafe { Vec::from_raw_parts(finalize_data as *mut Data, length, capacity) };
1550}
1551
1552impl_typed_array!(Int8Array, i8, TypedArrayType::Int8);
1553impl_from_slice!(Int8Array, Int8ArraySlice, i8, TypedArrayType::Int8);
1554impl_typed_array!(Uint8Array, u8, TypedArrayType::Uint8);
1555impl_from_slice!(Uint8Array, Uint8ArraySlice, u8, TypedArrayType::Uint8);
1556impl_typed_array!(Uint8ClampedArray, u8, TypedArrayType::Uint8Clamped);
1557impl_typed_array!(Int16Array, i16, TypedArrayType::Int16);
1558impl_from_slice!(Int16Array, Int16ArraySlice, i16, TypedArrayType::Int16);
1559impl_typed_array!(Uint16Array, u16, TypedArrayType::Uint16);
1560impl_from_slice!(Uint16Array, Uint16ArraySlice, u16, TypedArrayType::Uint16);
1561impl_typed_array!(Int32Array, i32, TypedArrayType::Int32);
1562impl_from_slice!(Int32Array, Int32ArraySlice, i32, TypedArrayType::Int32);
1563impl_typed_array!(Uint32Array, u32, TypedArrayType::Uint32);
1564impl_from_slice!(Uint32Array, Uint32ArraySlice, u32, TypedArrayType::Uint32);
1565impl_typed_array!(Float32Array, f32, TypedArrayType::Float32);
1566impl_from_slice!(
1567 Float32Array,
1568 Float32ArraySlice,
1569 f32,
1570 TypedArrayType::Float32
1571);
1572impl_typed_array!(Float64Array, f64, TypedArrayType::Float64);
1573impl_from_slice!(
1574 Float64Array,
1575 Float64ArraySlice,
1576 f64,
1577 TypedArrayType::Float64
1578);
1579#[cfg(feature = "napi6")]
1580impl_typed_array!(BigInt64Array, i64, TypedArrayType::BigInt64);
1581#[cfg(feature = "napi6")]
1582impl_from_slice!(
1583 BigInt64Array,
1584 BigInt64ArraySlice,
1585 i64,
1586 TypedArrayType::BigInt64
1587);
1588#[cfg(feature = "napi6")]
1589impl_typed_array!(BigUint64Array, u64, TypedArrayType::BigUint64);
1590#[cfg(feature = "napi6")]
1591impl_from_slice!(
1592 BigUint64Array,
1593 BigUint64ArraySlice,
1594 u64,
1595 TypedArrayType::BigUint64
1596);
1597
1598impl Uint8Array {
1599 pub fn from_string(mut s: String) -> Self {
1601 let len = s.len();
1602 let cap = s.capacity();
1603 let ret = Self {
1604 data: s.as_mut_ptr(),
1605 length: len,
1606 capacity: cap,
1607 finalizer_notify: Box::into_raw(Box::new(move |data, _| {
1608 drop(unsafe { String::from_raw_parts(data, len, cap) });
1609 })),
1610 byte_offset: 0,
1611 raw: None,
1612 #[cfg(all(feature = "napi4", not(feature = "noop")))]
1613 custom_gc_handle: None,
1614 };
1615 mem::forget(s);
1616 ret
1617 }
1618}
1619
1620#[derive(Clone, Copy)]
1621pub struct Uint8ClampedSlice<'scope> {
1625 pub(crate) inner: NonNull<u8>,
1626 pub(crate) length: usize,
1627 raw_value: sys::napi_value,
1628 env: sys::napi_env,
1629 _marker: PhantomData<&'scope ()>,
1630}
1631
1632impl FromNapiValue for Uint8ClampedSlice<'_> {
1633 unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
1634 let mut typed_array_type = 0;
1635 let mut length = 0;
1636 let mut data = ptr::null_mut();
1637 let mut array_buffer = ptr::null_mut();
1638 let mut byte_offset = 0;
1639 check_status!(
1640 unsafe {
1641 sys::napi_get_typedarray_info(
1642 env,
1643 napi_val,
1644 &mut typed_array_type,
1645 &mut length,
1646 &mut data,
1647 &mut array_buffer,
1648 &mut byte_offset,
1649 )
1650 },
1651 "Get TypedArray info failed"
1652 )?;
1653 if typed_array_type != TypedArrayType::Uint8Clamped as i32 {
1654 return Err(Error::new(
1655 Status::InvalidArg,
1656 format!("Expected $name, got {typed_array_type}"),
1657 ));
1658 }
1659 Ok(Self {
1660 inner: if length == 0 {
1661 NonNull::dangling()
1662 } else {
1663 unsafe { NonNull::new_unchecked(data.cast()) }
1664 },
1665 length,
1666 raw_value: napi_val,
1667 env,
1668 _marker: PhantomData,
1669 })
1670 }
1671}
1672
1673impl<'env> JsValue<'env> for Uint8ClampedSlice<'env> {
1674 fn value(&self) -> Value {
1675 Value {
1676 env: self.env,
1677 value: self.raw_value,
1678 value_type: ValueType::Object,
1679 }
1680 }
1681}
1682
1683impl<'env> JsObjectValue<'env> for Uint8ClampedSlice<'env> {}
1684
1685impl TypeName for Uint8ClampedSlice<'_> {
1686 fn type_name() -> &'static str {
1687 "Uint8ClampedArray"
1688 }
1689
1690 fn value_type() -> ValueType {
1691 ValueType::Object
1692 }
1693}
1694
1695impl ValidateNapiValue for Uint8ClampedSlice<'_> {
1696 unsafe fn validate(env: sys::napi_env, napi_val: sys::napi_value) -> Result<sys::napi_value> {
1697 let mut is_typedarray = false;
1698 check_status!(
1699 unsafe { sys::napi_is_typedarray(env, napi_val, &mut is_typedarray) },
1700 "Failed to validate typed buffer"
1701 )?;
1702 if !is_typedarray {
1703 return Err(Error::new(
1704 Status::InvalidArg,
1705 "Expected a TypedArray value".to_owned(),
1706 ));
1707 }
1708 Ok(ptr::null_mut())
1709 }
1710}
1711
1712impl AsRef<[u8]> for Uint8ClampedSlice<'_> {
1713 fn as_ref(&self) -> &[u8] {
1714 unsafe { core::slice::from_raw_parts(self.inner.as_ptr(), self.length) }
1715 }
1716}
1717
1718impl Deref for Uint8ClampedSlice<'_> {
1719 type Target = [u8];
1720
1721 fn deref(&self) -> &Self::Target {
1722 unsafe { core::slice::from_raw_parts(self.inner.as_ptr(), self.length) }
1723 }
1724}
1725
1726impl<'env> Uint8ClampedSlice<'env> {
1727 pub fn from_data<D: Into<Vec<u8>>>(env: &Env, data: D) -> Result<Self> {
1729 let mut buf = ptr::null_mut();
1730 let mut data: Vec<u8> = data.into();
1731 let mut inner_ptr = data.as_mut_ptr();
1732 #[cfg(all(debug_assertions, not(windows), not(target_family = "wasm")))]
1733 {
1734 let is_existed = super::BUFFER_DATA.with(|buffer_data| {
1735 let buffer = buffer_data.lock().expect("Unlock buffer data failed");
1736 buffer.contains(&inner_ptr)
1737 });
1738 if is_existed {
1739 panic!("Share the same data between different buffers is not allowed, see: https://github.com/nodejs/node/issues/32463#issuecomment-631974747");
1740 }
1741 }
1742 let len = data.len();
1743 let cap = data.capacity();
1744 let finalize_hint = Box::into_raw(Box::new((len, cap)));
1745 let mut status = unsafe {
1746 sys::napi_create_external_arraybuffer(
1747 env.0,
1748 inner_ptr.cast(),
1749 data.len(),
1750 Some(finalize_slice::<u8>),
1751 finalize_hint.cast(),
1752 &mut buf,
1753 )
1754 };
1755 if status == napi_sys::Status::napi_no_external_buffers_allowed {
1756 unsafe {
1757 let _ = Box::from_raw(finalize_hint);
1758 }
1759 let mut underlying_data = ptr::null_mut();
1760 status = unsafe { sys::napi_create_arraybuffer(env.0, len, &mut underlying_data, &mut buf) };
1761 check_status!(status, "Failed to create arraybuffer")?;
1762 if len > 0 {
1763 let underlying_slice: &mut [u8] =
1764 unsafe { std::slice::from_raw_parts_mut(underlying_data.cast(), len) };
1765 underlying_slice.copy_from_slice(data.as_slice());
1766 }
1767 inner_ptr = underlying_data.cast();
1768 } else {
1769 check_status!(status, "Failed to create arraybuffer")?;
1770 mem::forget(data);
1771 }
1772
1773 let mut napi_val = ptr::null_mut();
1774 check_status!(
1775 unsafe {
1776 sys::napi_create_typedarray(
1777 env.0,
1778 TypedArrayType::Uint8Clamped as i32,
1779 len,
1780 buf,
1781 0,
1782 &mut napi_val,
1783 )
1784 },
1785 "Create TypedArray failed"
1786 )?;
1787
1788 Ok(Self {
1789 inner: if len == 0 {
1790 NonNull::dangling()
1791 } else {
1792 unsafe { NonNull::new_unchecked(inner_ptr.cast()) }
1793 },
1794 length: len,
1795 raw_value: napi_val,
1796 env: env.0,
1797 _marker: PhantomData,
1798 })
1799 }
1800
1801 pub unsafe fn from_external<T: 'env, F: FnOnce(Env, T)>(
1821 env: &Env,
1822 data: *mut u8,
1823 len: usize,
1824 finalize_hint: T,
1825 finalize_callback: F,
1826 ) -> Result<Self> {
1827 if data.is_null() || std::ptr::eq(data, crate::EMPTY_VEC.as_ptr()) {
1828 return Err(Error::new(
1829 Status::InvalidArg,
1830 "Borrowed data should not be null".to_owned(),
1831 ));
1832 }
1833 #[cfg(all(debug_assertions, not(windows), not(target_family = "wasm")))]
1834 {
1835 let is_existed = super::BUFFER_DATA.with(|buffer_data| {
1836 let buffer = buffer_data.lock().expect("Unlock buffer data failed");
1837 buffer.contains(&data)
1838 });
1839 if is_existed {
1840 panic!("Share the same data between different buffers is not allowed, see: https://github.com/nodejs/node/issues/32463#issuecomment-631974747");
1841 }
1842 }
1843 let hint_ptr = Box::into_raw(Box::new((finalize_hint, finalize_callback)));
1844 let mut arraybuffer_value = ptr::null_mut();
1845 let mut status = unsafe {
1846 sys::napi_create_external_arraybuffer(
1847 env.0,
1848 data.cast(),
1849 len,
1850 Some(crate::env::raw_finalize_with_custom_callback::<T, F>),
1851 hint_ptr.cast(),
1852 &mut arraybuffer_value,
1853 )
1854 };
1855 let mut inner_ptr: *mut u8 = data;
1858 if status == sys::Status::napi_no_external_buffers_allowed {
1859 let (hint, finalize) = *Box::from_raw(hint_ptr);
1860 let mut underlying_data = ptr::null_mut();
1861 status = unsafe {
1862 sys::napi_create_arraybuffer(env.0, len, &mut underlying_data, &mut arraybuffer_value)
1863 };
1864 if status == sys::Status::napi_ok && len > 0 {
1866 let underlying_slice: &mut [u8] =
1867 unsafe { std::slice::from_raw_parts_mut(underlying_data.cast(), len) };
1868 underlying_slice.copy_from_slice(unsafe { std::slice::from_raw_parts(data, len) });
1869 }
1870 finalize(*env, hint);
1872 check_status!(status, "Failed to create arraybuffer from data")?;
1873 inner_ptr = underlying_data.cast();
1874 } else {
1875 check_status!(status, "Failed to create arraybuffer from data")?;
1876 }
1877
1878 let mut napi_val = ptr::null_mut();
1879 check_status!(
1880 unsafe {
1881 sys::napi_create_typedarray(
1882 env.0,
1883 TypedArrayType::Uint8Clamped as i32,
1884 len,
1885 arraybuffer_value,
1886 0,
1887 &mut napi_val,
1888 )
1889 },
1890 "Create TypedArray failed"
1891 )?;
1892
1893 Ok(Self {
1894 inner: if len == 0 {
1895 NonNull::dangling()
1896 } else {
1897 unsafe { NonNull::new_unchecked(inner_ptr) }
1898 },
1899 length: len,
1900 raw_value: napi_val,
1901 env: env.0,
1902 _marker: PhantomData,
1903 })
1904 }
1905
1906 pub fn copy_from<D: AsRef<[u8]>>(env: &Env, data: D) -> Result<Self> {
1908 let data = data.as_ref();
1909 let len = data.len();
1910 let mut arraybuffer_value = ptr::null_mut();
1911 let mut underlying_data = ptr::null_mut();
1912
1913 check_status!(
1914 unsafe {
1915 sys::napi_create_arraybuffer(env.0, len, &mut underlying_data, &mut arraybuffer_value)
1916 },
1917 "Failed to create ArrayBuffer"
1918 )?;
1919
1920 let mut napi_val = ptr::null_mut();
1921 check_status!(
1922 unsafe {
1923 sys::napi_create_typedarray(
1924 env.0,
1925 TypedArrayType::Uint8Clamped as i32,
1926 len,
1927 arraybuffer_value,
1928 0,
1929 &mut napi_val,
1930 )
1931 },
1932 "Create TypedArray failed"
1933 )?;
1934
1935 Ok(Self {
1936 inner: if len == 0 {
1937 NonNull::dangling()
1938 } else {
1939 unsafe { NonNull::new_unchecked(underlying_data.cast()) }
1940 },
1941 length: len,
1942 raw_value: napi_val,
1943 env: env.0,
1944 _marker: PhantomData,
1945 })
1946 }
1947
1948 pub fn from_arraybuffer(
1950 arraybuffer: &ArrayBuffer<'env>,
1951 byte_offset: usize,
1952 length: usize,
1953 ) -> Result<Self> {
1954 let env = arraybuffer.value.env;
1955 let mut typed_array = ptr::null_mut();
1956 check_status!(
1957 unsafe {
1958 sys::napi_create_typedarray(
1959 env,
1960 TypedArrayType::Uint8Clamped as i32,
1961 length,
1962 arraybuffer.value().value,
1963 byte_offset,
1964 &mut typed_array,
1965 )
1966 },
1967 "Failed to create TypedArray from ArrayBuffer"
1968 )?;
1969
1970 unsafe { FromNapiValue::from_napi_value(env, typed_array) }
1971 }
1972
1973 pub fn assign_to_this<'a, U>(&self, this: This<'a, U>, name: &str) -> Result<Self>
1975 where
1976 U: FromNapiValue + JsObjectValue<'a>,
1977 {
1978 let name = CString::new(name)?;
1979 check_status!(
1980 unsafe {
1981 sys::napi_set_named_property(self.env, this.object.raw(), name.as_ptr(), self.raw_value)
1982 },
1983 "Failed to assign {} to this",
1984 Self::type_name()
1985 )?;
1986 Ok(Self {
1987 env: self.env,
1988 raw_value: self.raw_value,
1989 inner: self.inner,
1990 length: self.length,
1991 _marker: PhantomData,
1992 })
1993 }
1994
1995 #[allow(clippy::should_implement_trait)]
1996 pub unsafe fn as_mut(&mut self) -> &mut [u8] {
2001 core::slice::from_raw_parts_mut(self.inner.as_ptr(), self.length)
2002 }
2003
2004 pub fn into_typed_array(self, env: &Env) -> Result<Self> {
2006 unsafe { Self::from_napi_value(env.0, self.raw_value) }
2007 }
2008}
2009
2010impl<T: Into<Vec<u8>>> From<T> for Uint8Array {
2011 fn from(data: T) -> Self {
2012 Uint8Array::new(data.into())
2013 }
2014}
2015
2016impl<T: Into<Vec<u8>>> From<T> for Uint8ClampedArray {
2017 fn from(data: T) -> Self {
2018 Uint8ClampedArray::new(data.into())
2019 }
2020}
2021
2022impl<T: Into<Vec<u16>>> From<T> for Uint16Array {
2023 fn from(data: T) -> Self {
2024 Uint16Array::new(data.into())
2025 }
2026}
2027
2028impl<T: Into<Vec<u32>>> From<T> for Uint32Array {
2029 fn from(data: T) -> Self {
2030 Uint32Array::new(data.into())
2031 }
2032}
2033
2034impl<T: Into<Vec<i8>>> From<T> for Int8Array {
2035 fn from(data: T) -> Self {
2036 Int8Array::new(data.into())
2037 }
2038}
2039
2040impl<T: Into<Vec<i16>>> From<T> for Int16Array {
2041 fn from(data: T) -> Self {
2042 Int16Array::new(data.into())
2043 }
2044}
2045
2046impl<T: Into<Vec<i32>>> From<T> for Int32Array {
2047 fn from(data: T) -> Self {
2048 Int32Array::new(data.into())
2049 }
2050}
2051
2052impl<T: Into<Vec<f32>>> From<T> for Float32Array {
2053 fn from(data: T) -> Self {
2054 Float32Array::new(data.into())
2055 }
2056}
2057
2058impl<T: Into<Vec<f64>>> From<T> for Float64Array {
2059 fn from(data: T) -> Self {
2060 Float64Array::new(data.into())
2061 }
2062}
2063
2064#[cfg(feature = "napi6")]
2065impl<T: Into<Vec<i64>>> From<T> for BigInt64Array {
2066 fn from(data: T) -> Self {
2067 BigInt64Array::new(data.into())
2068 }
2069}
2070#[cfg(feature = "napi6")]
2071impl<T: Into<Vec<u64>>> From<T> for BigUint64Array {
2072 fn from(data: T) -> Self {
2073 BigUint64Array::new(data.into())
2074 }
2075}