Repository: napi-rs/napi-rs
File: crates/napi/src/bindgen_runtime/js_values/arraybuffer.rs (Rust)

Code before:
    let ret = Self {
      data: s.as_mut_ptr(),
      length: len,
      finalizer_notify: Box::into_raw(Box::new(move |data, _| {
        drop(unsafe { String::from_raw_parts(data, len, cap) });
      })),
      byte_offset: 0,
      raw: None,
    };
    mem::forget(s);
    ret
  }
}

#[derive(Clone, Copy)]
/// Zero copy Uint8ClampedArray slice shared between Rust and Node.js.
/// It can only be used in non-async context and the lifetime is bound to the fn closure.
/// If you want to use Node.js `Uint8ClampedArray` in async context or want to extend the lifetime, use `Uint8ClampedArray` instead.
pub struct Uint8ClampedSlice<'scope> {
  pub(crate) inner: NonNull<u8>,
  pub(crate) length: usize,
  raw_value: sys::napi_value,
  env: sys::napi_env,
  _marker: PhantomData<&'scope ()>,
}

impl FromNapiValue for Uint8ClampedSlice<'_> {
  unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
    let mut typed_array_type = 0;
    let mut length = 0;
    let mut data = ptr::null_mut();
    let mut array_buffer = ptr::null_mut();
    let mut byte_offset = 0;
    check_status!(
      unsafe {
        sys::napi_get_typedarray_info(
          env,
          napi_val,
          &mut typed_array_type,
          &mut length,
          &mut data,
          &mut array_buffer,
          &mut byte_offset,
        )
      },
      "Get TypedArray info failed"
    )?;
    if typed_array_type != TypedArrayType::Uint8Clamped as i32 {
      return Err(Error::new(
        Status::InvalidArg,
        format!("Expected $name, got {typed_array_type}"),

Review comment (suggestion):
The captured `cap` variable in the closure may not match the actual capacity at the time the finalizer runs if the String was reallocated. Consider capturing `s.capacity()` at the time of finalizer creation or ensuring the String doesn't get reallocated.

Code after:
  BigInt64Array,
  BigInt64ArraySlice,
  i64,
  TypedArrayType::BigInt64
);
#[cfg(feature = "napi6")]
impl_typed_array!(BigUint64Array, u64, TypedArrayType::BigUint64);
#[cfg(feature = "napi6")]
impl_from_slice!(
  BigUint64Array,
  BigUint64ArraySlice,
  u64,
  TypedArrayType::BigUint64
);

impl Uint8Array {
  /// Create a new JavaScript `Uint8Array` from a Rust `String` without copying the underlying data.
  pub fn from_string(mut s: String) -> Self {
    let len = s.len();
    let cap = s.capacity();
    let ret = Self {
      data: s.as_mut_ptr(),
      length: len,
      capacity: cap,
      finalizer_notify: Box::into_raw(Box::new(move |data, _| {
        drop(unsafe { String::from_raw_parts(data, len, cap) });
      })),
      byte_offset: 0,
      raw: None,
    };
    mem::forget(s);
    ret
  }
}

#[derive(Clone, Copy)]
/// Zero copy Uint8ClampedArray slice shared between Rust and Node.js.
/// It can only be used in non-async context and the lifetime is bound to the fn closure.
/// If you want to use Node.js `Uint8ClampedArray` in async context or want to extend the lifetime, use `Uint8ClampedArray` instead.
pub struct Uint8ClampedSlice<'scope> {
  pub(crate) inner: NonNull<u8>,
  pub(crate) length: usize,
  raw_value: sys::napi_value,
  env: sys::napi_env,
  _marker: PhantomData<&'scope ()>,
}

impl FromNapiValue for Uint8ClampedSlice<'_> {
  unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
    let mut typed_array_type = 0;
    let mut length = 0;