1use std::ffi::{c_void, CString};
2use std::marker::PhantomData;
3use std::mem;
4use std::ops::Deref;
5use std::ptr::{self, NonNull};
6#[cfg(all(feature = "napi4", not(feature = "noop")))]
7use std::sync::atomic::Ordering;
8
9#[cfg(all(feature = "napi4", not(feature = "noop")))]
10use crate::bindgen_prelude::{CUSTOM_GC_TSFN, CUSTOM_GC_TSFN_DESTROYED, THREADS_CAN_ACCESS_ENV};
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 FromNapiValue for ArrayBuffer<'_> {
115 unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
116 let value = Value {
117 env,
118 value: napi_val,
119 value_type: ValueType::Object,
120 };
121 let mut data = ptr::null_mut();
122 let mut byte_length = 0;
123 check_status!(unsafe {
124 sys::napi_get_arraybuffer_info(env, napi_val, &mut data, &mut byte_length)
125 })?;
126 Ok(ArrayBuffer {
127 value,
128 data: if data.is_null() {
129 &[]
130 } else {
131 unsafe { std::slice::from_raw_parts(data as *const u8, byte_length) }
132 },
133 })
134 }
135}
136
137impl Deref for ArrayBuffer<'_> {
138 type Target = [u8];
139
140 fn deref(&self) -> &Self::Target {
141 self.data
142 }
143}
144
145impl<'env> ArrayBuffer<'env> {
146 pub fn from_data<D: Into<Vec<u8>>>(env: &Env, data: D) -> Result<Self> {
148 let mut buf = ptr::null_mut();
149 let mut data = data.into();
150 let mut inner_ptr = data.as_mut_ptr();
151 #[cfg(all(debug_assertions, not(windows)))]
152 {
153 let is_existed = super::BUFFER_DATA.with(|buffer_data| {
154 let buffer = buffer_data.lock().expect("Unlock buffer data failed");
155 buffer.contains(&inner_ptr)
156 });
157 if is_existed {
158 panic!("Share the same data between different buffers is not allowed, see: https://github.com/nodejs/node/issues/32463#issuecomment-631974747");
159 }
160 }
161 let len = data.len();
162 let mut status = unsafe {
163 sys::napi_create_external_arraybuffer(
164 env.0,
165 inner_ptr.cast(),
166 data.len(),
167 Some(finalize_slice::<u8>),
168 Box::into_raw(Box::new(len)).cast(),
169 &mut buf,
170 )
171 };
172 if status == napi_sys::Status::napi_no_external_buffers_allowed {
173 let mut underlying_data = ptr::null_mut();
174 status =
175 unsafe { sys::napi_create_arraybuffer(env.0, data.len(), &mut underlying_data, &mut buf) };
176 let underlying_slice: &mut [u8] =
177 unsafe { std::slice::from_raw_parts_mut(underlying_data.cast(), data.len()) };
178 underlying_slice.copy_from_slice(data.as_slice());
179 inner_ptr = underlying_data.cast();
180 } else {
181 mem::forget(data);
182 }
183 check_status!(status, "Failed to create buffer slice from data")?;
184 Ok(Self {
185 value: Value {
186 env: env.0,
187 value: buf,
188 value_type: ValueType::Object,
189 },
190 data: if len == 0 {
191 &[]
192 } else {
193 unsafe { std::slice::from_raw_parts(inner_ptr.cast(), len) }
194 },
195 })
196 }
197
198 pub unsafe fn from_external<T: 'env, F: FnOnce(Env, T)>(
215 env: &Env,
216 data: *mut u8,
217 len: usize,
218 finalize_hint: T,
219 finalize_callback: F,
220 ) -> Result<Self> {
221 if data.is_null() || std::ptr::eq(data, crate::EMPTY_VEC.as_ptr()) {
222 return Err(Error::new(
223 Status::InvalidArg,
224 "Borrowed data should not be null".to_owned(),
225 ));
226 }
227 #[cfg(all(debug_assertions, not(windows)))]
228 {
229 let is_existed = super::BUFFER_DATA.with(|buffer_data| {
230 let buffer = buffer_data.lock().expect("Unlock buffer data failed");
231 buffer.contains(&data)
232 });
233 if is_existed {
234 panic!("Share the same data between different buffers is not allowed, see: https://github.com/nodejs/node/issues/32463#issuecomment-631974747");
235 }
236 }
237 let hint_ptr = Box::into_raw(Box::new((finalize_hint, finalize_callback)));
238 let mut arraybuffer_value = ptr::null_mut();
239 let mut status = unsafe {
240 sys::napi_create_external_arraybuffer(
241 env.0,
242 data.cast(),
243 len,
244 Some(crate::env::raw_finalize_with_custom_callback::<T, F>),
245 hint_ptr.cast(),
246 &mut arraybuffer_value,
247 )
248 };
249 status = if status == sys::Status::napi_no_external_buffers_allowed {
250 let (hint, finalize) = *Box::from_raw(hint_ptr);
251 let mut underlying_data = ptr::null_mut();
252 let status = unsafe {
253 sys::napi_create_arraybuffer(env.0, len, &mut underlying_data, &mut arraybuffer_value)
254 };
255 unsafe { std::ptr::copy_nonoverlapping(data.cast(), underlying_data, len) };
256 finalize(*env, hint);
257 status
258 } else {
259 status
260 };
261 check_status!(status, "Failed to create arraybuffer from data")?;
262
263 Ok(Self {
264 value: Value {
265 env: env.0,
266 value: arraybuffer_value,
267 value_type: ValueType::Object,
268 },
269 data: if len == 0 {
270 &[]
271 } else {
272 unsafe { std::slice::from_raw_parts(data.cast(), len) }
273 },
274 })
275 }
276
277 pub fn copy_from<D: AsRef<[u8]>>(env: &Env, data: D) -> Result<Self> {
279 let data = data.as_ref();
280 let len = data.len();
281 let mut arraybuffer_value = ptr::null_mut();
282 let mut underlying_data = ptr::null_mut();
283
284 check_status!(
285 unsafe {
286 sys::napi_create_arraybuffer(env.0, len, &mut underlying_data, &mut arraybuffer_value)
287 },
288 "Failed to create ArrayBuffer"
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(underlying_data.cast(), len) }
301 },
302 })
303 }
304
305 #[cfg(feature = "napi7")]
306 pub fn detach(self) -> Result<()> {
312 check_status!(unsafe { sys::napi_detach_arraybuffer(self.value.env, self.value.value) })
313 }
314
315 #[cfg(feature = "napi7")]
316 pub fn is_detached(&self) -> Result<bool> {
320 let mut is_detached = false;
321 check_status!(unsafe {
322 sys::napi_is_detached_arraybuffer(self.value.env, self.value.value, &mut is_detached)
323 })?;
324 Ok(is_detached)
325 }
326}
327
328#[derive(Clone, Copy)]
329pub struct TypedArray<'env> {
331 pub(crate) value: Value,
332 pub typed_array_type: TypedArrayType,
333 pub arraybuffer: ArrayBuffer<'env>,
334 pub byte_offset: usize,
335}
336
337impl TypeName for TypedArray<'_> {
338 fn type_name() -> &'static str {
339 "TypedArray"
340 }
341
342 fn value_type() -> ValueType {
343 ValueType::Object
344 }
345}
346
347impl ValidateNapiValue for TypedArray<'_> {
348 unsafe fn validate(env: sys::napi_env, napi_val: sys::napi_value) -> Result<sys::napi_value> {
349 let mut is_typedarray = false;
350 check_status!(
351 unsafe { sys::napi_is_typedarray(env, napi_val, &mut is_typedarray) },
352 "Failed to validate TypedArray"
353 )?;
354 if !is_typedarray {
355 return Err(Error::new(
356 Status::InvalidArg,
357 "Value is not a TypedArray".to_owned(),
358 ));
359 }
360 Ok(ptr::null_mut())
361 }
362}
363
364impl<'env> JsValue<'env> for TypedArray<'env> {
365 fn value(&self) -> Value {
366 self.value
367 }
368}
369
370impl<'env> JsObjectValue<'env> for TypedArray<'env> {}
371
372impl FromNapiValue for TypedArray<'_> {
373 unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
374 let value = Value {
375 env,
376 value: napi_val,
377 value_type: ValueType::Object,
378 };
379 let mut typed_array_type = 0;
380 let mut data = ptr::null_mut();
381 let mut length = 0;
382 let mut arraybuffer = ptr::null_mut();
383 let mut byte_offset = 0;
384 check_status!(
385 unsafe {
386 sys::napi_get_typedarray_info(
387 env,
388 napi_val,
389 &mut typed_array_type,
390 &mut length,
391 &mut data,
392 &mut arraybuffer,
393 &mut byte_offset,
394 )
395 },
396 "Failed to get typedarray info"
397 )?;
398 Ok(Self {
399 value: Value {
400 env,
401 value: napi_val,
402 value_type: ValueType::Object,
403 },
404 typed_array_type: typed_array_type.into(),
405 byte_offset,
406 arraybuffer: ArrayBuffer {
407 value,
408 data: if data.is_null() {
409 &[]
410 } else {
411 unsafe { std::slice::from_raw_parts(data as *const u8, length) }
412 },
413 },
414 })
415 }
416}
417
418trait Finalizer {
419 type RustType;
420
421 fn finalizer_notify(&self) -> *mut dyn FnOnce(*mut Self::RustType, usize);
422}
423
424macro_rules! impl_typed_array {
425 ($name:ident, $rust_type:ident, $typed_array_type:expr) => {
426 pub struct $name {
427 data: *mut $rust_type,
428 length: usize,
429 #[allow(unused)]
430 byte_offset: usize,
431 raw: Option<(crate::sys::napi_ref, crate::sys::napi_env)>,
432 finalizer_notify: *mut dyn FnOnce(*mut $rust_type, usize),
433 }
434
435 unsafe impl Send for $name {}
438 unsafe impl Sync for $name {}
439
440 impl Finalizer for $name {
441 type RustType = $rust_type;
442
443 fn finalizer_notify(&self) -> *mut dyn FnOnce(*mut Self::RustType, usize) {
444 self.finalizer_notify
445 }
446 }
447
448 impl Drop for $name {
449 fn drop(&mut self) {
450 if let Some((ref_, env)) = self.raw {
451 if ref_.is_null() || env.is_null() {
454 return;
455 }
456 #[cfg(all(feature = "napi4", not(feature = "noop")))]
457 {
458 if CUSTOM_GC_TSFN_DESTROYED.load(Ordering::SeqCst) {
459 return;
460 }
461 if !THREADS_CAN_ACCESS_ENV.with(|cell| cell.get()) {
462 let status = unsafe {
463 sys::napi_call_threadsafe_function(
464 CUSTOM_GC_TSFN.load(std::sync::atomic::Ordering::SeqCst),
465 ref_.cast(),
466 1,
467 )
468 };
469 assert!(
470 status == sys::Status::napi_ok || status == sys::Status::napi_closing,
471 "Call custom GC in ArrayBuffer::drop failed {}",
472 Status::from(status)
473 );
474 return;
475 }
476 }
477 let mut ref_count = 0;
478 crate::check_status_or_throw!(
479 env,
480 unsafe { sys::napi_reference_unref(env, ref_, &mut ref_count) },
481 "Failed to unref ArrayBuffer reference in drop"
482 );
483 debug_assert!(
484 ref_count == 0,
485 "ArrayBuffer reference count in ArrayBuffer::drop is not zero"
486 );
487 crate::check_status_or_throw!(
488 env,
489 unsafe { sys::napi_delete_reference(env, ref_) },
490 "Failed to delete ArrayBuffer reference in drop"
491 );
492 return;
493 }
494 if !self.finalizer_notify().is_null() {
496 let finalizer = unsafe { Box::from_raw(self.finalizer_notify) };
497 (finalizer)(self.data, self.length);
498 return;
499 }
500 if !self.data.is_null() {
501 let length = self.length;
502 unsafe { Vec::from_raw_parts(self.data, length, length) };
503 }
504 }
505 }
506
507 impl $name {
508 #[cfg(target_family = "wasm")]
509 pub fn sync(&mut self, env: &crate::Env) {
510 if let Some((reference, _)) = self.raw {
511 let mut value = ptr::null_mut();
512 let mut array_buffer = ptr::null_mut();
513 crate::check_status_or_throw!(
514 env.raw(),
515 unsafe { crate::sys::napi_get_reference_value(env.raw(), reference, &mut value) },
516 "Failed to get reference value from TypedArray while syncing"
517 );
518 crate::check_status_or_throw!(
519 env.raw(),
520 unsafe {
521 crate::sys::napi_get_typedarray_info(
522 env.raw(),
523 value,
524 &mut ($typed_array_type as i32) as *mut i32,
525 &mut self.length as *mut usize,
526 ptr::null_mut(),
527 &mut array_buffer,
528 &mut self.byte_offset as *mut usize,
529 )
530 },
531 "Failed to get ArrayBuffer under the TypedArray while syncing"
532 );
533 crate::check_status_or_throw!(
534 env.raw(),
535 unsafe {
536 emnapi_sync_memory(
537 env.raw(),
538 false,
539 array_buffer,
540 self.byte_offset,
541 self.length,
542 )
543 },
544 "Failed to sync memory"
545 );
546 } else {
547 return;
548 }
549 }
550
551 pub fn new(mut data: Vec<$rust_type>) -> Self {
552 data.shrink_to_fit();
553 let ret = $name {
554 data: data.as_mut_ptr(),
555 length: data.len(),
556 byte_offset: 0,
557 raw: None,
558 finalizer_notify: ptr::null_mut::<fn(*mut $rust_type, usize)>(),
559 };
560 mem::forget(data);
561 ret
562 }
563
564 pub fn with_data_copied<D>(data: D) -> Self
565 where
566 D: AsRef<[$rust_type]>,
567 {
568 let mut data_copied = data.as_ref().to_vec();
569 let ret = $name {
570 data: data_copied.as_mut_ptr(),
571 length: data.as_ref().len(),
572 finalizer_notify: ptr::null_mut::<fn(*mut $rust_type, usize)>(),
573 raw: None,
574 byte_offset: 0,
575 };
576 mem::forget(data_copied);
577 ret
578 }
579
580 pub unsafe fn with_external_data<F>(data: *mut $rust_type, length: usize, notify: F) -> Self
584 where
585 F: 'static + FnOnce(*mut $rust_type, usize),
586 {
587 $name {
588 data,
589 length,
590 finalizer_notify: Box::into_raw(Box::new(notify)),
591 raw: None,
592 byte_offset: 0,
593 }
594 }
595
596 #[allow(clippy::should_implement_trait)]
597 pub unsafe fn as_mut(&mut self) -> &mut [$rust_type] {
602 if self.data.is_null() {
603 return &mut [];
604 }
605
606 unsafe { std::slice::from_raw_parts_mut(self.data, self.length) }
607 }
608 }
609
610 impl Deref for $name {
611 type Target = [$rust_type];
612
613 fn deref(&self) -> &Self::Target {
614 self.as_ref()
615 }
616 }
617
618 impl AsRef<[$rust_type]> for $name {
619 fn as_ref(&self) -> &[$rust_type] {
620 if self.data.is_null() {
621 return &[];
622 }
623
624 unsafe { std::slice::from_raw_parts(self.data, self.length) }
625 }
626 }
627
628 impl TypeName for $name {
629 fn type_name() -> &'static str {
630 concat!("TypedArray<", stringify!($rust_type), ">")
631 }
632
633 fn value_type() -> crate::ValueType {
634 crate::ValueType::Object
635 }
636 }
637
638 impl ValidateNapiValue for $name {
639 unsafe fn validate(
640 env: sys::napi_env,
641 napi_val: sys::napi_value,
642 ) -> Result<crate::sys::napi_value> {
643 let mut is_typed_array = false;
644 check_status!(
645 unsafe { sys::napi_is_typedarray(env, napi_val, &mut is_typed_array) },
646 "Failed to check if value is typed array"
647 )?;
648 if !is_typed_array {
649 return Err(Error::new(
650 Status::InvalidArg,
651 "Expected a TypedArray value".to_owned(),
652 ));
653 }
654 Ok(ptr::null_mut())
655 }
656 }
657
658 impl FromNapiValue for $name {
659 unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
660 let mut typed_array_type = 0;
661 let mut length = 0;
662 let mut data = ptr::null_mut();
663 let mut array_buffer = ptr::null_mut();
664 let mut byte_offset = 0;
665 let mut ref_ = ptr::null_mut();
666 check_status!(
667 unsafe { sys::napi_create_reference(env, napi_val, 1, &mut ref_) },
668 "Failed to create reference from TypedArray"
669 )?;
670 check_status!(
671 unsafe {
672 sys::napi_get_typedarray_info(
673 env,
674 napi_val,
675 &mut typed_array_type,
676 &mut length,
677 &mut data,
678 &mut array_buffer,
679 &mut byte_offset,
680 )
681 },
682 "Get TypedArray info failed"
683 )?;
684 if typed_array_type != $typed_array_type as i32 {
685 return Err(Error::new(
686 Status::InvalidArg,
687 format!(
688 "Expected {}, got {}Array",
689 stringify!($name),
690 TypedArrayType::from(typed_array_type).as_ref()
691 ),
692 ));
693 }
694 Ok($name {
695 data: data.cast(),
696 length,
697 byte_offset,
698 raw: Some((ref_, env)),
699 finalizer_notify: ptr::null_mut::<fn(*mut $rust_type, usize)>(),
700 })
701 }
702 }
703
704 impl ToNapiValue for $name {
705 unsafe fn to_napi_value(env: sys::napi_env, mut val: Self) -> Result<sys::napi_value> {
706 if let Some((ref_, _)) = val.raw {
707 let mut napi_value = std::ptr::null_mut();
708 check_status!(
709 unsafe { sys::napi_get_reference_value(env, ref_, &mut napi_value) },
710 "Failed to get reference from ArrayBuffer"
711 )?;
712 check_status!(
713 unsafe { sys::napi_delete_reference(env, ref_) },
714 "Failed to delete reference in ArrayBuffer::to_napi_value"
715 )?;
716 val.raw = Some((ptr::null_mut(), ptr::null_mut()));
717 return Ok(napi_value);
718 }
719 let mut arraybuffer_value = ptr::null_mut();
720 let ratio = mem::size_of::<$rust_type>();
721 let val_length = val.length;
722 let length = val_length * ratio;
723 let val_data = val.data;
724 check_status!(
725 if length == 0 {
726 unsafe {
730 sys::napi_create_arraybuffer(env, length, ptr::null_mut(), &mut arraybuffer_value)
731 }
732 } else {
733 let hint_ptr = Box::into_raw(Box::new(val));
734 let status = unsafe {
735 sys::napi_create_external_arraybuffer(
736 env,
737 val_data.cast(),
738 length,
739 Some(finalizer::<$rust_type, $name>),
740 hint_ptr.cast(),
741 &mut arraybuffer_value,
742 )
743 };
744 if status == napi_sys::Status::napi_no_external_buffers_allowed {
745 let hint = unsafe { Box::from_raw(hint_ptr) };
746 let mut underlying_data = ptr::null_mut();
747 let status = unsafe {
748 sys::napi_create_arraybuffer(
749 env,
750 length,
751 &mut underlying_data,
752 &mut arraybuffer_value,
753 )
754 };
755 unsafe { std::ptr::copy_nonoverlapping(hint.data.cast(), underlying_data, length) };
756 status
757 } else {
758 status
759 }
760 },
761 "Create external arraybuffer failed"
762 )?;
763 let mut napi_val = ptr::null_mut();
764 check_status!(
765 unsafe {
766 sys::napi_create_typedarray(
767 env,
768 $typed_array_type as i32,
769 val_length,
770 arraybuffer_value,
771 0,
772 &mut napi_val,
773 )
774 },
775 "Create TypedArray failed"
776 )?;
777 Ok(napi_val)
778 }
779 }
780
781 impl ToNapiValue for &mut $name {
782 unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
783 if let Some((ref_, _)) = val.raw {
784 let mut napi_value = std::ptr::null_mut();
785 check_status!(
786 unsafe { sys::napi_get_reference_value(env, ref_, &mut napi_value) },
787 "Failed to get reference from ArrayBuffer"
788 )?;
789 return Ok(napi_value);
790 }
791 let mut arraybuffer_value = ptr::null_mut();
792 let ratio = mem::size_of::<$rust_type>();
793 let val_length = val.length;
794 let length = val_length * ratio;
795 let val_data = val.data;
796 let mut copied_val = None;
797 check_status!(
798 if length == 0 {
799 unsafe {
803 sys::napi_create_arraybuffer(env, length, ptr::null_mut(), &mut arraybuffer_value)
804 }
805 } else {
806 let val_copy = $name {
809 data: val.data,
810 length: val.length,
811 byte_offset: val.byte_offset,
812 raw: None,
813 finalizer_notify: val.finalizer_notify,
814 };
815 let hint_ref: &mut $name = Box::leak(Box::new(val_copy));
816 let hint_ptr = hint_ref as *mut $name;
817 copied_val = Some(hint_ref);
818 let status = unsafe {
819 sys::napi_create_external_arraybuffer(
820 env,
821 val_data.cast(),
822 length,
823 Some(finalizer::<$rust_type, $name>),
824 hint_ptr.cast(),
825 &mut arraybuffer_value,
826 )
827 };
828 if status == napi_sys::Status::napi_no_external_buffers_allowed {
829 let hint = unsafe { Box::from_raw(hint_ptr) };
830 let mut underlying_data = ptr::null_mut();
831 let status = unsafe {
832 sys::napi_create_arraybuffer(
833 env,
834 length,
835 &mut underlying_data,
836 &mut arraybuffer_value,
837 )
838 };
839 unsafe { std::ptr::copy_nonoverlapping(hint.data.cast(), underlying_data, length) };
840 status
841 } else {
842 status
843 }
844 },
845 "Create external arraybuffer failed"
846 )?;
847 let mut napi_val = ptr::null_mut();
848 check_status!(
849 unsafe {
850 sys::napi_create_typedarray(
851 env,
852 $typed_array_type as i32,
853 val_length,
854 arraybuffer_value,
855 0,
856 &mut napi_val,
857 )
858 },
859 "Create TypedArray failed"
860 )?;
861 let mut ref_ = ptr::null_mut();
862 check_status!(
863 unsafe { sys::napi_create_reference(env, napi_val, 1, &mut ref_) },
864 "Failed to delete reference in ArrayBuffer::to_napi_value"
865 )?;
866 val.raw = Some((ref_, env));
867 if let Some(copied_val) = copied_val {
868 val.finalizer_notify = ptr::null_mut::<fn(*mut $rust_type, usize)>();
869 val.data = ptr::null_mut();
870 val.length = 0;
871 copied_val.raw = Some((ref_, ptr::null_mut()));
872 }
873 Ok(napi_val)
874 }
875 }
876 };
877}
878
879macro_rules! impl_from_slice {
880 ($name:ident, $slice_type:ident, $rust_type:ident, $typed_array_type:expr) => {
881 #[derive(Clone, Copy)]
882 pub struct $slice_type<'env> {
883 pub(crate) inner: NonNull<$rust_type>,
884 pub(crate) length: usize,
885 raw_value: sys::napi_value,
886 env: sys::napi_env,
887 _marker: PhantomData<&'env ()>,
888 }
889
890 impl <'env> $slice_type<'env> {
891 #[doc = " Create a new `"]
892 #[doc = stringify!($slice_type)]
893 #[doc = "` from a `Vec<"]
894 #[doc = stringify!($rust_type)]
895 #[doc = ">`."]
896 pub fn from_data<D: Into<Vec<u8>>>(env: &Env, data: D) -> Result<Self> {
897 let mut buf = ptr::null_mut();
898 let mut data = data.into();
899 let mut inner_ptr = data.as_mut_ptr();
900 #[cfg(all(debug_assertions, not(windows)))]
901 {
902 let is_existed = super::BUFFER_DATA.with(|buffer_data| {
903 let buffer = buffer_data.lock().expect("Unlock buffer data failed");
904 buffer.contains(&inner_ptr)
905 });
906 if is_existed {
907 panic!("Share the same data between different buffers is not allowed, see: https://github.com/nodejs/node/issues/32463#issuecomment-631974747");
908 }
909 }
910 let len = data.len();
911 let mut status = unsafe {
912 sys::napi_create_external_arraybuffer(
913 env.0,
914 inner_ptr.cast(),
915 data.len(),
916 Some(finalize_slice::<$rust_type>),
917 Box::into_raw(Box::new(len)).cast(),
918 &mut buf,
919 )
920 };
921 if status == napi_sys::Status::napi_no_external_buffers_allowed {
922 let mut underlying_data = ptr::null_mut();
923 status = unsafe {
924 sys::napi_create_arraybuffer(
925 env.0,
926 data.len(),
927 &mut underlying_data,
928 &mut buf,
929 )
930 };
931 let underlying_slice: &mut [u8] =
932 unsafe { std::slice::from_raw_parts_mut(underlying_data.cast(), data.len()) };
933 underlying_slice.copy_from_slice(data.as_slice());
934 inner_ptr = underlying_data.cast();
935 } else {
936 mem::forget(data);
937 }
938 check_status!(status, "Failed to create buffer slice from data")?;
939
940 let mut napi_val = ptr::null_mut();
941 check_status!(
942 unsafe {
943 sys::napi_create_typedarray(
944 env.0,
945 $typed_array_type as i32,
946 len,
947 buf,
948 0,
949 &mut napi_val,
950 )
951 },
952 "Create TypedArray failed"
953 )?;
954
955 Ok(Self {
956 inner: if len == 0 {
957 NonNull::dangling()
958 } else {
959 unsafe { NonNull::new_unchecked(inner_ptr.cast()) }
960 },
961 length: len,
962 raw_value: napi_val,
963 env: env.0,
964 _marker: PhantomData,
965 })
966 }
967
968 #[doc = "## Safety"]
969 #[doc = ""]
970 #[doc = "Mostly the same with `from_data`"]
971 #[doc = ""]
972 #[doc = "Provided `finalize_callback` will be called when `"]
973 #[doc = stringify!($slice_type)]
974 #[doc = "` got dropped."]
975 #[doc = ""]
976 #[doc = "You can pass in `noop_finalize` if you have nothing to do in finalize phase."]
977 #[doc = ""]
978 #[doc = "### Notes"]
979 #[doc = ""]
980 #[doc = "JavaScript may mutate the data passed in to this buffer when writing the buffer."]
981 #[doc = "However, some JavaScript runtimes do not support external buffers (notably electron!)"]
982 #[doc = "in which case modifications may be lost."]
983 #[doc = ""]
984 #[doc = "If you need to support these runtimes, you should create a buffer by other means and then"]
985 #[doc = "later copy the data back out."]
986 pub unsafe fn from_external<T: 'env, F: FnOnce(Env, T)>(
987 env: &Env,
988 data: *mut u8,
989 len: usize,
990 finalize_hint: T,
991 finalize_callback: F,
992 ) -> Result<Self> {
993 if data.is_null() || data as *const u8 == crate::EMPTY_VEC.as_ptr() {
994 return Err(Error::new(
995 Status::InvalidArg,
996 "Borrowed data should not be null".to_owned(),
997 ));
998 }
999 #[cfg(all(debug_assertions, not(windows)))]
1000 {
1001 let is_existed = super::BUFFER_DATA.with(|buffer_data| {
1002 let buffer = buffer_data.lock().expect("Unlock buffer data failed");
1003 buffer.contains(&data)
1004 });
1005 if is_existed {
1006 panic!("Share the same data between different buffers is not allowed, see: https://github.com/nodejs/node/issues/32463#issuecomment-631974747");
1007 }
1008 }
1009 let hint_ptr = Box::into_raw(Box::new((finalize_hint, finalize_callback)));
1010 let mut arraybuffer_value = ptr::null_mut();
1011 let mut status = unsafe {
1012 sys::napi_create_external_arraybuffer(
1013 env.0,
1014 data.cast(),
1015 len,
1016 Some(crate::env::raw_finalize_with_custom_callback::<T, F>),
1017 hint_ptr.cast(),
1018 &mut arraybuffer_value,
1019 )
1020 };
1021 status = if status == sys::Status::napi_no_external_buffers_allowed {
1022 let (hint, finalize) = *Box::from_raw(hint_ptr);
1023 let mut underlying_data = ptr::null_mut();
1024 let status = unsafe {
1025 sys::napi_create_arraybuffer(
1026 env.0,
1027 len,
1028 &mut underlying_data,
1029 &mut arraybuffer_value,
1030 )
1031 };
1032 let underlying_slice: &mut [u8] =
1033 unsafe { std::slice::from_raw_parts_mut(underlying_data.cast(), len) };
1034 underlying_slice.copy_from_slice(unsafe { std::slice::from_raw_parts(data, len) });
1035 finalize(*env, hint);
1036 status
1037 } else {
1038 status
1039 };
1040 check_status!(status, "Failed to create arraybuffer from data")?;
1041
1042 let mut napi_val = ptr::null_mut();
1043 check_status!(
1044 unsafe {
1045 sys::napi_create_typedarray(
1046 env.0,
1047 $typed_array_type as i32,
1048 len,
1049 arraybuffer_value,
1050 0,
1051 &mut napi_val,
1052 )
1053 },
1054 "Create TypedArray failed"
1055 )?;
1056
1057 Ok(Self {
1058 inner: if len == 0 {
1059 NonNull::dangling()
1060 } else {
1061 unsafe { NonNull::new_unchecked(data.cast()) }
1062 },
1063 length: len,
1064 raw_value: napi_val,
1065 env: env.0,
1066 _marker: PhantomData,
1067 })
1068 }
1069
1070 #[doc = "Copy data from a `&["]
1071 #[doc = stringify!($rust_type)]
1072 #[doc = "]` and create a `"]
1073 #[doc = stringify!($slice_type)]
1074 #[doc = "` from it."]
1075 pub fn copy_from<D: AsRef<[$rust_type]>>(env: &Env, data: D) -> Result<Self> {
1076 let data = data.as_ref();
1077 let len = data.len();
1078 let mut arraybuffer_value = ptr::null_mut();
1079 let mut underlying_data = ptr::null_mut();
1080
1081 check_status!(
1082 unsafe {
1083 sys::napi_create_arraybuffer(
1084 env.0,
1085 len,
1086 &mut underlying_data,
1087 &mut arraybuffer_value,
1088 )
1089 },
1090 "Failed to create ArrayBuffer"
1091 )?;
1092
1093 let mut napi_val = ptr::null_mut();
1094 check_status!(
1095 unsafe {
1096 sys::napi_create_typedarray(
1097 env.0,
1098 $typed_array_type as i32,
1099 len,
1100 arraybuffer_value,
1101 0,
1102 &mut napi_val,
1103 )
1104 },
1105 "Create TypedArray failed"
1106 )?;
1107
1108 Ok(Self {
1109 inner: if len == 0 {
1110 NonNull::dangling()
1111 } else {
1112 unsafe { NonNull::new_unchecked(underlying_data.cast()) }
1113 },
1114 length: len,
1115 raw_value: napi_val,
1116 env: env.0,
1117 _marker: PhantomData,
1118 })
1119 }
1120
1121 pub fn from_arraybuffer(arraybuffer: &ArrayBuffer<'env>, byte_offset: usize, length: usize) -> Result<$slice_type<'env>> {
1123 let env = arraybuffer.value.env;
1124 let mut typed_array = ptr::null_mut();
1125 check_status!(unsafe {
1126 sys::napi_create_typedarray(env, $typed_array_type.into(), length, arraybuffer.value().value, byte_offset, &mut typed_array)
1127 }, "Failed to create TypedArray from ArrayBuffer")?;
1128
1129 unsafe { FromNapiValue::from_napi_value(env, typed_array) }
1130 }
1131
1132 pub fn assign_to_this<'a, U>(&self, this: This<'a, U>, name: &str) -> Result<$slice_type<'a>>
1134 where
1135 U: FromNapiValue + JsObjectValue<'a>,
1136 {
1137 let name = CString::new(name)?;
1138 check_status!(
1139 unsafe { sys::napi_set_named_property(self.env, this.object.raw(), name.as_ptr(), self.raw_value) },
1140 "Failed to assign {} to this",
1141 $slice_type::type_name()
1142 )?;
1143 Ok($slice_type {
1144 env: self.env,
1145 raw_value: self.raw_value,
1146 inner: self.inner,
1147 length: self.length,
1148 _marker: PhantomData,
1149 })
1150 }
1151
1152 #[allow(clippy::should_implement_trait)]
1153 pub unsafe fn as_mut(&mut self) -> &mut [$rust_type] {
1158 unsafe { core::slice::from_raw_parts_mut(self.inner.as_ptr(), self.length) }
1159 }
1160
1161 #[doc = "Convert a `"]
1162 #[doc = stringify!($slice_type)]
1163 #[doc = "` to a `"]
1164 #[doc = stringify!($name)]
1165 #[doc = "`."]
1166 #[doc = ""]
1167 #[doc = "This will perform a `napi_create_reference` internally."]
1168 pub fn into_typed_array(self, env: &Env) -> Result<$name> {
1169 unsafe { $name::from_napi_value(env.0, self.raw_value) }
1170 }
1171 }
1172
1173 impl<'env> JsValue<'env> for $slice_type<'env> {
1174 fn value(&self) -> Value {
1175 Value {
1176 env: self.env,
1177 value: self.raw_value,
1178 value_type: ValueType::Object,
1179 }
1180 }
1181 }
1182
1183 impl<'env> JsObjectValue<'env> for $slice_type<'env> { }
1184
1185 impl ToNapiValue for &$slice_type<'_> {
1186 unsafe fn to_napi_value(_: sys::napi_env, val: Self) -> Result<sys::napi_value> {
1187 Ok(val.raw_value)
1188 }
1189 }
1190
1191 impl ToNapiValue for &mut $slice_type<'_> {
1192 unsafe fn to_napi_value(_: sys::napi_env, val: Self) -> Result<sys::napi_value> {
1193 Ok(val.raw_value)
1194 }
1195 }
1196
1197 impl FromNapiValue for $slice_type<'_> {
1198 unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
1199 let mut typed_array_type = 0;
1200 let mut length = 0;
1201 let mut data = ptr::null_mut();
1202 let mut array_buffer = ptr::null_mut();
1203 let mut byte_offset = 0;
1204 check_status!(
1205 unsafe {
1206 sys::napi_get_typedarray_info(
1207 env,
1208 napi_val,
1209 &mut typed_array_type,
1210 &mut length,
1211 &mut data,
1212 &mut array_buffer,
1213 &mut byte_offset,
1214 )
1215 },
1216 "Get TypedArray info failed"
1217 )?;
1218 if typed_array_type != $typed_array_type as i32 {
1219 return Err(Error::new(
1220 Status::InvalidArg,
1221 format!("Expected $name, got {}", typed_array_type),
1222 ));
1223 }
1224 Ok(Self {
1232 inner: if length == 0 {
1233 ptr::NonNull::dangling()
1234 } else {
1235 ptr::NonNull::new_unchecked(data.cast())
1236 },
1237 length,
1238 raw_value: napi_val,
1239 env,
1240 _marker: PhantomData,
1241 })
1242 }
1243 }
1244
1245 impl TypeName for $slice_type<'_> {
1246 fn type_name() -> &'static str {
1247 concat!("TypedArray<", stringify!($rust_type), ">")
1248 }
1249
1250 fn value_type() -> crate::ValueType {
1251 crate::ValueType::Object
1252 }
1253 }
1254
1255 impl ValidateNapiValue for $slice_type<'_> {
1256 unsafe fn validate(env: sys::napi_env, napi_val: sys::napi_value) -> Result<sys::napi_value> {
1257 let mut is_typed_array = false;
1258 check_status!(
1259 unsafe { sys::napi_is_typedarray(env, napi_val, &mut is_typed_array) },
1260 "Failed to validate napi typed array"
1261 )?;
1262 if !is_typed_array {
1263 return Err(Error::new(
1264 Status::InvalidArg,
1265 "Expected a TypedArray value".to_owned(),
1266 ));
1267 }
1268 Ok(ptr::null_mut())
1269 }
1270 }
1271
1272 impl AsRef<[$rust_type]> for $slice_type<'_> {
1273 fn as_ref(&self) -> &[$rust_type] {
1274 unsafe { core::slice::from_raw_parts(self.inner.as_ptr(), self.length) }
1275 }
1276 }
1277
1278 impl Deref for $slice_type<'_> {
1279 type Target = [$rust_type];
1280
1281 fn deref(&self) -> &Self::Target {
1282 self.as_ref()
1283 }
1284 }
1285
1286 impl FromNapiValue for &mut [$rust_type] {
1287 unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
1288 let mut typed_array_type = 0;
1289 let mut length = 0;
1290 let mut data = ptr::null_mut();
1291 let mut array_buffer = ptr::null_mut();
1292 let mut byte_offset = 0;
1293 check_status!(
1294 unsafe {
1295 sys::napi_get_typedarray_info(
1296 env,
1297 napi_val,
1298 &mut typed_array_type,
1299 &mut length,
1300 &mut data,
1301 &mut array_buffer,
1302 &mut byte_offset,
1303 )
1304 },
1305 "Get TypedArray info failed"
1306 )?;
1307 if typed_array_type != $typed_array_type as i32 {
1308 return Err(Error::new(
1309 Status::InvalidArg,
1310 format!("Expected $name, got {}", typed_array_type),
1311 ));
1312 }
1313 Ok(if length == 0 {
1314 &mut []
1315 } else {
1316 unsafe { core::slice::from_raw_parts_mut(data as *mut $rust_type, length) }
1317 })
1318 }
1319 }
1320
1321 impl FromNapiValue for &[$rust_type] {
1322 unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
1323 let mut typed_array_type = 0;
1324 let mut length = 0;
1325 let mut data = ptr::null_mut();
1326 let mut array_buffer = ptr::null_mut();
1327 let mut byte_offset = 0;
1328 check_status!(
1329 unsafe {
1330 sys::napi_get_typedarray_info(
1331 env,
1332 napi_val,
1333 &mut typed_array_type,
1334 &mut length,
1335 &mut data,
1336 &mut array_buffer,
1337 &mut byte_offset,
1338 )
1339 },
1340 "Get TypedArray info failed"
1341 )?;
1342 if typed_array_type != $typed_array_type as i32 {
1343 return Err(Error::new(
1344 Status::InvalidArg,
1345 format!("Expected $name, got {}", typed_array_type),
1346 ));
1347 }
1348 Ok(if length == 0 {
1349 &[]
1350 } else {
1351 unsafe { core::slice::from_raw_parts_mut(data as *mut $rust_type, length) }
1352 })
1353 }
1354 }
1355
1356 impl TypeName for &mut [$rust_type] {
1357 fn type_name() -> &'static str {
1358 concat!("TypedArray<", stringify!($rust_type), ">")
1359 }
1360
1361 fn value_type() -> crate::ValueType {
1362 crate::ValueType::Object
1363 }
1364 }
1365
1366 impl TypeName for &[$rust_type] {
1367 fn type_name() -> &'static str {
1368 concat!("TypedArray<", stringify!($rust_type), ">")
1369 }
1370
1371 fn value_type() -> crate::ValueType {
1372 crate::ValueType::Object
1373 }
1374 }
1375
1376 impl ValidateNapiValue for &[$rust_type] {
1377 unsafe fn validate(env: sys::napi_env, napi_val: sys::napi_value) -> Result<sys::napi_value> {
1378 let mut is_typed_array = false;
1379 check_status!(
1380 unsafe { sys::napi_is_typedarray(env, napi_val, &mut is_typed_array) },
1381 "Failed to validate napi typed array"
1382 )?;
1383 if !is_typed_array {
1384 return Err(Error::new(
1385 Status::InvalidArg,
1386 "Expected a TypedArray value".to_owned(),
1387 ));
1388 }
1389 Ok(ptr::null_mut())
1390 }
1391 }
1392
1393 impl ValidateNapiValue for &mut [$rust_type] {
1394 unsafe fn validate(env: sys::napi_env, napi_val: sys::napi_value) -> Result<sys::napi_value> {
1395 let mut is_typed_array = false;
1396 check_status!(
1397 unsafe { sys::napi_is_typedarray(env, napi_val, &mut is_typed_array) },
1398 "Failed to validate napi typed array"
1399 )?;
1400 if !is_typed_array {
1401 return Err(Error::new(
1402 Status::InvalidArg,
1403 "Expected a TypedArray value".to_owned(),
1404 ));
1405 }
1406 Ok(ptr::null_mut())
1407 }
1408 }
1409 };
1410}
1411
1412unsafe extern "C" fn finalizer<Data, T: Finalizer<RustType = Data> + AsRef<[Data]>>(
1413 _env: sys::napi_env,
1414 _finalize_data: *mut c_void,
1415 finalize_hint: *mut c_void,
1416) {
1417 let data = unsafe { *Box::from_raw(finalize_hint as *mut T) };
1418 drop(data);
1419}
1420
1421unsafe extern "C" fn finalize_slice<Data>(
1422 _env: sys::napi_env,
1423 finalize_data: *mut c_void,
1424 finalize_hint: *mut c_void,
1425) {
1426 let length = unsafe { *Box::from_raw(finalize_hint as *mut usize) };
1427 unsafe { Vec::from_raw_parts(finalize_data as *mut Data, length, length) };
1428}
1429
1430impl_typed_array!(Int8Array, i8, TypedArrayType::Int8);
1431impl_from_slice!(Int8Array, Int8ArraySlice, i8, TypedArrayType::Int8);
1432impl_typed_array!(Uint8Array, u8, TypedArrayType::Uint8);
1433impl_from_slice!(Uint8Array, Uint8ArraySlice, u8, TypedArrayType::Uint8);
1434impl_typed_array!(Uint8ClampedArray, u8, TypedArrayType::Uint8Clamped);
1435impl_typed_array!(Int16Array, i16, TypedArrayType::Int16);
1436impl_from_slice!(Int16Array, Int16ArraySlice, i16, TypedArrayType::Int16);
1437impl_typed_array!(Uint16Array, u16, TypedArrayType::Uint16);
1438impl_from_slice!(Uint16Array, Uint16ArraySlice, u16, TypedArrayType::Uint16);
1439impl_typed_array!(Int32Array, i32, TypedArrayType::Int32);
1440impl_from_slice!(Int32Array, Int32ArraySlice, i32, TypedArrayType::Int32);
1441impl_typed_array!(Uint32Array, u32, TypedArrayType::Uint32);
1442impl_from_slice!(Uint32Array, Uint32ArraySlice, u32, TypedArrayType::Uint32);
1443impl_typed_array!(Float32Array, f32, TypedArrayType::Float32);
1444impl_from_slice!(
1445 Float32Array,
1446 Float32ArraySlice,
1447 f32,
1448 TypedArrayType::Float32
1449);
1450impl_typed_array!(Float64Array, f64, TypedArrayType::Float64);
1451impl_from_slice!(
1452 Float64Array,
1453 Float64ArraySlice,
1454 f64,
1455 TypedArrayType::Float64
1456);
1457#[cfg(feature = "napi6")]
1458impl_typed_array!(BigInt64Array, i64, TypedArrayType::BigInt64);
1459#[cfg(feature = "napi6")]
1460impl_from_slice!(
1461 BigInt64Array,
1462 BigInt64ArraySlice,
1463 i64,
1464 TypedArrayType::BigInt64
1465);
1466#[cfg(feature = "napi6")]
1467impl_typed_array!(BigUint64Array, u64, TypedArrayType::BigUint64);
1468#[cfg(feature = "napi6")]
1469impl_from_slice!(
1470 BigUint64Array,
1471 BigUint64ArraySlice,
1472 u64,
1473 TypedArrayType::BigUint64
1474);
1475
1476impl Uint8Array {
1477 pub fn from_string(mut s: String) -> Self {
1479 let len = s.len();
1480 let ret = Self {
1481 data: s.as_mut_ptr(),
1482 length: len,
1483 finalizer_notify: Box::into_raw(Box::new(move |data, _| {
1484 drop(unsafe { String::from_raw_parts(data, len, len) });
1485 })),
1486 byte_offset: 0,
1487 raw: None,
1488 };
1489 mem::forget(s);
1490 ret
1491 }
1492}
1493
1494#[derive(Clone, Copy)]
1495pub struct Uint8ClampedSlice<'scope> {
1499 pub(crate) inner: NonNull<u8>,
1500 pub(crate) length: usize,
1501 raw_value: sys::napi_value,
1502 env: sys::napi_env,
1503 _marker: PhantomData<&'scope ()>,
1504}
1505
1506impl FromNapiValue for Uint8ClampedSlice<'_> {
1507 unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
1508 let mut typed_array_type = 0;
1509 let mut length = 0;
1510 let mut data = ptr::null_mut();
1511 let mut array_buffer = ptr::null_mut();
1512 let mut byte_offset = 0;
1513 check_status!(
1514 unsafe {
1515 sys::napi_get_typedarray_info(
1516 env,
1517 napi_val,
1518 &mut typed_array_type,
1519 &mut length,
1520 &mut data,
1521 &mut array_buffer,
1522 &mut byte_offset,
1523 )
1524 },
1525 "Get TypedArray info failed"
1526 )?;
1527 if typed_array_type != TypedArrayType::Uint8Clamped as i32 {
1528 return Err(Error::new(
1529 Status::InvalidArg,
1530 format!("Expected $name, got {typed_array_type}"),
1531 ));
1532 }
1533 Ok(Self {
1534 inner: if length == 0 {
1535 NonNull::dangling()
1536 } else {
1537 unsafe { NonNull::new_unchecked(data.cast()) }
1538 },
1539 length,
1540 raw_value: napi_val,
1541 env,
1542 _marker: PhantomData,
1543 })
1544 }
1545}
1546
1547impl<'env> JsValue<'env> for Uint8ClampedSlice<'env> {
1548 fn value(&self) -> Value {
1549 Value {
1550 env: self.env,
1551 value: self.raw_value,
1552 value_type: ValueType::Object,
1553 }
1554 }
1555}
1556
1557impl<'env> JsObjectValue<'env> for Uint8ClampedSlice<'env> {}
1558
1559impl TypeName for Uint8ClampedSlice<'_> {
1560 fn type_name() -> &'static str {
1561 "Uint8ClampedArray"
1562 }
1563
1564 fn value_type() -> ValueType {
1565 ValueType::Object
1566 }
1567}
1568
1569impl ValidateNapiValue for Uint8ClampedSlice<'_> {
1570 unsafe fn validate(env: sys::napi_env, napi_val: sys::napi_value) -> Result<sys::napi_value> {
1571 let mut is_typedarray = false;
1572 check_status!(
1573 unsafe { sys::napi_is_typedarray(env, napi_val, &mut is_typedarray) },
1574 "Failed to validate typed buffer"
1575 )?;
1576 if !is_typedarray {
1577 return Err(Error::new(
1578 Status::InvalidArg,
1579 "Expected a TypedArray value".to_owned(),
1580 ));
1581 }
1582 Ok(ptr::null_mut())
1583 }
1584}
1585
1586impl AsRef<[u8]> for Uint8ClampedSlice<'_> {
1587 fn as_ref(&self) -> &[u8] {
1588 unsafe { core::slice::from_raw_parts(self.inner.as_ptr(), self.length) }
1589 }
1590}
1591
1592impl Deref for Uint8ClampedSlice<'_> {
1593 type Target = [u8];
1594
1595 fn deref(&self) -> &Self::Target {
1596 unsafe { core::slice::from_raw_parts(self.inner.as_ptr(), self.length) }
1597 }
1598}
1599
1600impl<'env> Uint8ClampedSlice<'env> {
1601 pub fn from_data<D: Into<Vec<u8>>>(env: &Env, data: D) -> Result<Self> {
1603 let mut buf = ptr::null_mut();
1604 let mut data: Vec<u8> = data.into();
1605 let mut inner_ptr = data.as_mut_ptr();
1606 #[cfg(all(debug_assertions, not(windows)))]
1607 {
1608 let is_existed = super::BUFFER_DATA.with(|buffer_data| {
1609 let buffer = buffer_data.lock().expect("Unlock buffer data failed");
1610 buffer.contains(&inner_ptr)
1611 });
1612 if is_existed {
1613 panic!("Share the same data between different buffers is not allowed, see: https://github.com/nodejs/node/issues/32463#issuecomment-631974747");
1614 }
1615 }
1616 let len = data.len();
1617 let mut status = unsafe {
1618 sys::napi_create_external_arraybuffer(
1619 env.0,
1620 inner_ptr.cast(),
1621 data.len(),
1622 Some(finalize_slice::<u8>),
1623 Box::into_raw(Box::new(len)).cast(),
1624 &mut buf,
1625 )
1626 };
1627 if status == napi_sys::Status::napi_no_external_buffers_allowed {
1628 let mut underlying_data = ptr::null_mut();
1629 status = unsafe { sys::napi_create_arraybuffer(env.0, len, &mut underlying_data, &mut buf) };
1630 let underlying_slice: &mut [u8] =
1631 unsafe { std::slice::from_raw_parts_mut(underlying_data.cast(), len) };
1632 underlying_slice.copy_from_slice(data.as_slice());
1633 inner_ptr = underlying_data.cast();
1634 } else {
1635 mem::forget(data);
1636 }
1637 check_status!(status, "Failed to create buffer slice from data")?;
1638
1639 let mut napi_val = ptr::null_mut();
1640 check_status!(
1641 unsafe {
1642 sys::napi_create_typedarray(
1643 env.0,
1644 TypedArrayType::Uint8Clamped as i32,
1645 len,
1646 buf,
1647 0,
1648 &mut napi_val,
1649 )
1650 },
1651 "Create TypedArray failed"
1652 )?;
1653
1654 Ok(Self {
1655 inner: if len == 0 {
1656 NonNull::dangling()
1657 } else {
1658 unsafe { NonNull::new_unchecked(inner_ptr.cast()) }
1659 },
1660 length: len,
1661 raw_value: napi_val,
1662 env: env.0,
1663 _marker: PhantomData,
1664 })
1665 }
1666
1667 pub unsafe fn from_external<T: 'env, F: FnOnce(Env, T)>(
1686 env: &Env,
1687 data: *mut u8,
1688 len: usize,
1689 finalize_hint: T,
1690 finalize_callback: F,
1691 ) -> Result<Self> {
1692 if data.is_null() || std::ptr::eq(data, crate::EMPTY_VEC.as_ptr()) {
1693 return Err(Error::new(
1694 Status::InvalidArg,
1695 "Borrowed data should not be null".to_owned(),
1696 ));
1697 }
1698 #[cfg(all(debug_assertions, not(windows)))]
1699 {
1700 let is_existed = super::BUFFER_DATA.with(|buffer_data| {
1701 let buffer = buffer_data.lock().expect("Unlock buffer data failed");
1702 buffer.contains(&data)
1703 });
1704 if is_existed {
1705 panic!("Share the same data between different buffers is not allowed, see: https://github.com/nodejs/node/issues/32463#issuecomment-631974747");
1706 }
1707 }
1708 let hint_ptr = Box::into_raw(Box::new((finalize_hint, finalize_callback)));
1709 let mut arraybuffer_value = ptr::null_mut();
1710 let mut status = unsafe {
1711 sys::napi_create_external_arraybuffer(
1712 env.0,
1713 data.cast(),
1714 len,
1715 Some(crate::env::raw_finalize_with_custom_callback::<T, F>),
1716 hint_ptr.cast(),
1717 &mut arraybuffer_value,
1718 )
1719 };
1720 status = if status == sys::Status::napi_no_external_buffers_allowed {
1721 let (hint, finalize) = *Box::from_raw(hint_ptr);
1722 let mut underlying_data = ptr::null_mut();
1723 let status = unsafe {
1724 sys::napi_create_arraybuffer(env.0, len, &mut underlying_data, &mut arraybuffer_value)
1725 };
1726 let underlying_slice: &mut [u8] =
1727 unsafe { std::slice::from_raw_parts_mut(underlying_data.cast(), len) };
1728 underlying_slice.copy_from_slice(unsafe { std::slice::from_raw_parts(data, len) });
1729 finalize(*env, hint);
1730 status
1731 } else {
1732 status
1733 };
1734 check_status!(status, "Failed to create arraybuffer from data")?;
1735
1736 let mut napi_val = ptr::null_mut();
1737 check_status!(
1738 unsafe {
1739 sys::napi_create_typedarray(
1740 env.0,
1741 TypedArrayType::Uint8Clamped as i32,
1742 len,
1743 arraybuffer_value,
1744 0,
1745 &mut napi_val,
1746 )
1747 },
1748 "Create TypedArray failed"
1749 )?;
1750
1751 Ok(Self {
1752 inner: if len == 0 {
1753 NonNull::dangling()
1754 } else {
1755 unsafe { NonNull::new_unchecked(data.cast()) }
1756 },
1757 length: len,
1758 raw_value: napi_val,
1759 env: env.0,
1760 _marker: PhantomData,
1761 })
1762 }
1763
1764 pub fn copy_from<D: AsRef<[u8]>>(env: &Env, data: D) -> Result<Self> {
1766 let data = data.as_ref();
1767 let len = data.len();
1768 let mut arraybuffer_value = ptr::null_mut();
1769 let mut underlying_data = ptr::null_mut();
1770
1771 check_status!(
1772 unsafe {
1773 sys::napi_create_arraybuffer(env.0, len, &mut underlying_data, &mut arraybuffer_value)
1774 },
1775 "Failed to create ArrayBuffer"
1776 )?;
1777
1778 let mut napi_val = ptr::null_mut();
1779 check_status!(
1780 unsafe {
1781 sys::napi_create_typedarray(
1782 env.0,
1783 TypedArrayType::Uint8Clamped as i32,
1784 len,
1785 arraybuffer_value,
1786 0,
1787 &mut napi_val,
1788 )
1789 },
1790 "Create TypedArray failed"
1791 )?;
1792
1793 Ok(Self {
1794 inner: if len == 0 {
1795 NonNull::dangling()
1796 } else {
1797 unsafe { NonNull::new_unchecked(underlying_data.cast()) }
1798 },
1799 length: len,
1800 raw_value: napi_val,
1801 env: env.0,
1802 _marker: PhantomData,
1803 })
1804 }
1805
1806 pub fn from_arraybuffer(
1808 arraybuffer: &ArrayBuffer<'env>,
1809 byte_offset: usize,
1810 length: usize,
1811 ) -> Result<Self> {
1812 let env = arraybuffer.value.env;
1813 let mut typed_array = ptr::null_mut();
1814 check_status!(
1815 unsafe {
1816 sys::napi_create_typedarray(
1817 env,
1818 TypedArrayType::Uint8Clamped as i32,
1819 length,
1820 arraybuffer.value().value,
1821 byte_offset,
1822 &mut typed_array,
1823 )
1824 },
1825 "Failed to create TypedArray from ArrayBuffer"
1826 )?;
1827
1828 unsafe { FromNapiValue::from_napi_value(env, typed_array) }
1829 }
1830
1831 pub fn assign_to_this<'a, U>(&self, this: This<'a, U>, name: &str) -> Result<Self>
1833 where
1834 U: FromNapiValue + JsObjectValue<'a>,
1835 {
1836 let name = CString::new(name)?;
1837 check_status!(
1838 unsafe {
1839 sys::napi_set_named_property(self.env, this.object.raw(), name.as_ptr(), self.raw_value)
1840 },
1841 "Failed to assign {} to this",
1842 Self::type_name()
1843 )?;
1844 Ok(Self {
1845 env: self.env,
1846 raw_value: self.raw_value,
1847 inner: self.inner,
1848 length: self.length,
1849 _marker: PhantomData,
1850 })
1851 }
1852
1853 #[allow(clippy::should_implement_trait)]
1854 pub unsafe fn as_mut(&mut self) -> &mut [u8] {
1859 core::slice::from_raw_parts_mut(self.inner.as_ptr(), self.length)
1860 }
1861
1862 pub fn into_typed_array(self, env: &Env) -> Result<Self> {
1864 unsafe { Self::from_napi_value(env.0, self.raw_value) }
1865 }
1866}
1867
1868impl<T: Into<Vec<u8>>> From<T> for Uint8Array {
1869 fn from(data: T) -> Self {
1870 Uint8Array::new(data.into())
1871 }
1872}
1873
1874impl<T: Into<Vec<u8>>> From<T> for Uint8ClampedArray {
1875 fn from(data: T) -> Self {
1876 Uint8ClampedArray::new(data.into())
1877 }
1878}
1879
1880impl<T: Into<Vec<u16>>> From<T> for Uint16Array {
1881 fn from(data: T) -> Self {
1882 Uint16Array::new(data.into())
1883 }
1884}
1885
1886impl<T: Into<Vec<u32>>> From<T> for Uint32Array {
1887 fn from(data: T) -> Self {
1888 Uint32Array::new(data.into())
1889 }
1890}
1891
1892impl<T: Into<Vec<i8>>> From<T> for Int8Array {
1893 fn from(data: T) -> Self {
1894 Int8Array::new(data.into())
1895 }
1896}
1897
1898impl<T: Into<Vec<i16>>> From<T> for Int16Array {
1899 fn from(data: T) -> Self {
1900 Int16Array::new(data.into())
1901 }
1902}
1903
1904impl<T: Into<Vec<i32>>> From<T> for Int32Array {
1905 fn from(data: T) -> Self {
1906 Int32Array::new(data.into())
1907 }
1908}
1909
1910impl<T: Into<Vec<f32>>> From<T> for Float32Array {
1911 fn from(data: T) -> Self {
1912 Float32Array::new(data.into())
1913 }
1914}
1915
1916impl<T: Into<Vec<f64>>> From<T> for Float64Array {
1917 fn from(data: T) -> Self {
1918 Float64Array::new(data.into())
1919 }
1920}
1921
1922#[cfg(feature = "napi6")]
1923impl<T: Into<Vec<i64>>> From<T> for BigInt64Array {
1924 fn from(data: T) -> Self {
1925 BigInt64Array::new(data.into())
1926 }
1927}
1928#[cfg(feature = "napi6")]
1929impl<T: Into<Vec<u64>>> From<T> for BigUint64Array {
1930 fn from(data: T) -> Self {
1931 BigUint64Array::new(data.into())
1932 }
1933}