napi/bindgen_runtime/js_values/
arraybuffer.rs

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  /// compatible with higher versions
37  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)]
100/// Represents a JavaScript ArrayBuffer
101pub 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  /// Create a new `ArrayBuffer` from a `Vec<u8>`.
147  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  /// ## Safety
199  ///
200  /// Mostly the same with `from_data`
201  ///
202  /// Provided `finalize_callback` will be called when `[u8]` got dropped.
203  ///
204  /// You can pass in `noop_finalize` if you have nothing to do in finalize phase.
205  ///
206  /// ### Notes
207  ///
208  /// JavaScript may mutate the data passed in to this buffer when writing the buffer.
209  /// However, some JavaScript runtimes do not support external buffers (notably electron!)
210  /// in which case modifications may be lost.
211  ///
212  /// If you need to support these runtimes, you should create a buffer by other means and then
213  /// later copy the data back out.
214  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  /// Copy data from a `&[u8]` and create a `ArrayBuffer` from it.
278  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  /// Generally, an ArrayBuffer is non-detachable if it has been detached before.
307  ///
308  /// The engine may impose additional conditions on whether an ArrayBuffer is detachable.
309  ///
310  /// For example, V8 requires that the ArrayBuffer be external, that is, created with napi_create_external_arraybuffer
311  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  /// The ArrayBuffer is considered `detached` if its internal data is null.
317  ///
318  /// This API represents the invocation of the `ArrayBuffer` `IsDetachedBuffer` operation as defined in [Section 24.1.1.2](https://tc39.es/ecma262/#sec-isdetachedbuffer) of the ECMAScript Language Specification.
319  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)]
329/// Represents a JavaScript ArrayBuffer
330pub 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    /// SAFETY: This is undefined behavior, as the JS side may always modify the underlying buffer,
436    /// without synchronization. Also see the docs for the `DerfMut` impl.
437    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 the ref is null, it means the TypedArray has been called `ToNapiValue::to_napi_value`, and the `ref` has been deleted
452          // If the env is null, it means the TypedArray is copied in `&mut TypedArray ToNapiValue::to_napi_value`, and the `ref` will be deleted in the raw TypedArray
453          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 the `finalizer_notify` is not null, it means the data is external, and we call the finalizer instead of the `Vec::from_raw_parts`
495        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      /// # Safety
581      ///
582      /// The caller will be notified when the data is deallocated by vm
583      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      /// # Safety
598      ///
599      /// This is literally undefined behavior, as the JS side may always modify the underlying buffer,
600      /// without synchronization.
601      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            // Rust uses 0x1 as the data pointer for empty buffers,
727            // but NAPI/V8 only allows multiple buffers to have
728            // the same data pointer if it's 0x0.
729            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            // Rust uses 0x1 as the data pointer for empty buffers,
800            // but NAPI/V8 only allows multiple buffers to have
801            // the same data pointer if it's 0x0.
802            unsafe {
803              sys::napi_create_arraybuffer(env, length, ptr::null_mut(), &mut arraybuffer_value)
804            }
805          } else {
806            // manually copy the data instead of implement `Clone` & `Copy` for TypedArray
807            // the TypedArray can't be copied if raw is not None
808            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      /// Create from `ArrayBuffer`
1122      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      /// extends the lifetime of the `TypedArray` to the lifetime of the `This`
1133      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      /// # Safety
1154      ///
1155      /// This is literally undefined behavior, as the JS side may always modify the underlying buffer,
1156      /// without synchronization.
1157      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        // From the docs of `napi_get_typedarray_info`:
1225        // > [out] data: The underlying data buffer of the node::Buffer. If length is 0, this may be
1226        // > NULL or any other pointer value.
1227        //
1228        // In order to guarantee that `slice::from_raw_parts` is sound, the pointer must be non-null, so
1229        // let's make sure it always is, even in the case of `napi_get_typedarray_info` returning a null
1230        // ptr.
1231        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  /// Create a new JavaScript `Uint8Array` from a Rust `String` without copying the underlying data.
1478  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)]
1495/// Zero copy Uint8ClampedArray slice shared between Rust and Node.js.
1496/// It can only be used in non-async context and the lifetime is bound to the fn closure.
1497/// If you want to use Node.js `Uint8ClampedArray` in async context or want to extend the lifetime, use `Uint8ClampedArray` instead.
1498pub 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  /// Create a new `Uint8ClampedSlice` from Vec<u8>
1602  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  /// ## Safety
1668  ///
1669  /// Mostly the same with `from_data`
1670  ///
1671  /// Provided `finalize_callback` will be called when `Uint8ClampedSlice` got dropped.
1672  ///
1673  /// You can pass in `noop_finalize` if you have nothing to do in finalize phase.
1674  ///
1675  /// ### Notes
1676  ///
1677  /// JavaScript may mutate the data passed in to this buffer when writing the buffer.
1678  ///
1679  /// However, some JavaScript runtimes do not support external buffers (notably electron!)
1680  ///
1681  /// in which case modifications may be lost.
1682  ///
1683  /// If you need to support these runtimes, you should create a buffer by other means and then
1684  /// later copy the data back out.
1685  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  /// Copy data from a `&[u8]` and create a `Uint8ClampedSlice` from it.
1765  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  /// Create from `ArrayBuffer`
1807  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  /// extends the lifetime of the `TypedArray` to the lifetime of the `This`
1832  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  /// # Safety
1855  ///
1856  /// This is literally undefined behavior, as the JS side may always modify the underlying buffer,
1857  /// without synchronization.
1858  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  /// Convert a `Uint8ClampedSlice` to a `Uint8ClampedArray`.
1863  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}