napi/js_values/
arraybuffer.rs

1use std::ops::{Deref, DerefMut};
2use std::os::raw::c_void;
3use std::ptr;
4use std::slice;
5
6use crate::{
7  bindgen_runtime::{FromNapiValue, TypeName, TypedArrayType, ValidateNapiValue},
8  check_status, sys, Env, Error, NapiValue, Ref, Result, Status, Unknown, Value, ValueType,
9};
10
11use super::JsValue;
12
13#[deprecated(
14  since = "3.0.0",
15  note = "Use `napi::bindgen_prelude::ArrayBuffer` instead"
16)]
17pub struct JsArrayBuffer(pub(crate) Value);
18
19impl TypeName for JsArrayBuffer {
20  fn type_name() -> &'static str {
21    "ArrayBuffer"
22  }
23
24  fn value_type() -> ValueType {
25    ValueType::Object
26  }
27}
28
29impl ValidateNapiValue for JsArrayBuffer {
30  unsafe fn validate(env: sys::napi_env, napi_val: sys::napi_value) -> Result<sys::napi_value> {
31    let mut is_array_buffer = false;
32    check_status!(unsafe { sys::napi_is_arraybuffer(env, napi_val, &mut is_array_buffer) })?;
33    if !is_array_buffer {
34      return Err(Error::new(
35        Status::InvalidArg,
36        "Value is not an array buffer".to_owned(),
37      ));
38    }
39    Ok(ptr::null_mut())
40  }
41}
42
43impl FromNapiValue for JsArrayBuffer {
44  unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
45    Ok(Self(Value {
46      env,
47      value: napi_val,
48      value_type: ValueType::Object,
49    }))
50  }
51}
52
53impl JsValue<'_> for JsArrayBuffer {
54  fn value(&self) -> Value {
55    self.0
56  }
57}
58
59#[deprecated(
60  since = "3.0.0",
61  note = "Use `napi::bindgen_prelude::ArrayBuffer` instead"
62)]
63pub struct JsArrayBufferValue {
64  pub value: JsArrayBuffer,
65  pub(crate) len: usize,
66  pub(crate) data: *mut c_void,
67}
68
69#[deprecated(
70  since = "3.0.0",
71  note = "Use `napi::bindgen_prelude::Uint8Array/Int8Array...` instead"
72)]
73pub struct JsTypedArray(pub(crate) Value);
74
75impl TypeName for JsTypedArray {
76  fn type_name() -> &'static str {
77    "TypedArray"
78  }
79
80  fn value_type() -> ValueType {
81    ValueType::Object
82  }
83}
84
85impl FromNapiValue for JsTypedArray {
86  unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
87    Ok(Self(Value {
88      env,
89      value: napi_val,
90      value_type: ValueType::Object,
91    }))
92  }
93}
94
95impl JsValue<'_> for JsTypedArray {
96  fn value(&self) -> Value {
97    self.0
98  }
99}
100
101#[deprecated(
102  since = "3.0.0",
103  note = "Use `napi::bindgen_prelude::Uint8Array/Int8Array...` instead"
104)]
105pub struct JsTypedArrayValue {
106  pub arraybuffer: JsArrayBuffer,
107  data: *mut c_void,
108  pub byte_offset: usize,
109  pub length: usize,
110  pub typedarray_type: TypedArrayType,
111}
112
113pub struct JsDataView(pub(crate) Value);
114
115impl TypeName for JsDataView {
116  fn type_name() -> &'static str {
117    "DataView"
118  }
119
120  fn value_type() -> ValueType {
121    ValueType::Object
122  }
123}
124
125pub struct JsDataViewValue {
126  pub arraybuffer: JsArrayBuffer,
127  _data: *mut c_void,
128  pub byte_offset: u64,
129  pub length: u64,
130}
131
132impl JsArrayBuffer {
133  #[cfg(feature = "napi7")]
134  pub fn detach(self) -> Result<()> {
135    check_status!(unsafe { sys::napi_detach_arraybuffer(self.0.env, self.0.value) })
136  }
137
138  #[cfg(feature = "napi7")]
139  pub fn is_detached(&self) -> Result<bool> {
140    let mut is_detached = false;
141    check_status!(unsafe {
142      sys::napi_is_detached_arraybuffer(self.0.env, self.0.value, &mut is_detached)
143    })?;
144    Ok(is_detached)
145  }
146
147  pub fn into_value(self) -> Result<JsArrayBufferValue> {
148    let mut data = ptr::null_mut();
149    let mut len: usize = 0;
150    check_status!(unsafe {
151      sys::napi_get_arraybuffer_info(self.0.env, self.0.value, &mut data, &mut len)
152    })?;
153    Ok(JsArrayBufferValue {
154      data,
155      value: self,
156      len,
157    })
158  }
159
160  pub fn into_typedarray(
161    self,
162    typedarray_type: TypedArrayType,
163    length: usize,
164    byte_offset: usize,
165  ) -> Result<JsTypedArray> {
166    let mut typedarray_value = ptr::null_mut();
167    check_status!(unsafe {
168      sys::napi_create_typedarray(
169        self.0.env,
170        typedarray_type.into(),
171        length,
172        self.0.value,
173        byte_offset,
174        &mut typedarray_value,
175      )
176    })?;
177    Ok(JsTypedArray(Value {
178      env: self.0.env,
179      value: typedarray_value,
180      value_type: ValueType::Object,
181    }))
182  }
183
184  pub fn into_dataview(self, length: usize, byte_offset: usize) -> Result<JsDataView> {
185    let mut dataview_value = ptr::null_mut();
186    check_status!(unsafe {
187      sys::napi_create_dataview(
188        self.0.env,
189        length,
190        self.0.value,
191        byte_offset,
192        &mut dataview_value,
193      )
194    })?;
195    Ok(JsDataView(Value {
196      env: self.0.env,
197      value: dataview_value,
198      value_type: ValueType::Object,
199    }))
200  }
201
202  pub fn into_ref(self) -> Result<Ref<JsArrayBuffer>> {
203    Ref::new(&Env::from(self.0.env), &self)
204  }
205}
206
207impl JsArrayBufferValue {
208  pub fn new(value: JsArrayBuffer, data: *mut c_void, len: usize) -> Self {
209    JsArrayBufferValue { value, len, data }
210  }
211
212  pub fn into_raw(self) -> JsArrayBuffer {
213    self.value
214  }
215
216  pub fn into_unknown<'env>(self) -> Unknown<'env> {
217    unsafe { Unknown::from_raw_unchecked(self.value.0.env, self.value.0.value) }
218  }
219}
220
221impl AsRef<[u8]> for JsArrayBufferValue {
222  fn as_ref(&self) -> &[u8] {
223    if self.data.is_null() {
224      return &[];
225    }
226    unsafe { slice::from_raw_parts(self.data as *const u8, self.len) }
227  }
228}
229
230impl AsMut<[u8]> for JsArrayBufferValue {
231  fn as_mut(&mut self) -> &mut [u8] {
232    if self.data.is_null() {
233      return &mut [];
234    }
235    unsafe { slice::from_raw_parts_mut(self.data as *mut u8, self.len) }
236  }
237}
238
239impl Deref for JsArrayBufferValue {
240  type Target = [u8];
241
242  fn deref(&self) -> &Self::Target {
243    self.as_ref()
244  }
245}
246
247impl DerefMut for JsArrayBufferValue {
248  fn deref_mut(&mut self) -> &mut Self::Target {
249    self.as_mut()
250  }
251}
252
253impl JsTypedArray {
254  /// get TypeArray info
255  /// <https://nodejs.org/api/n-api.html#n_api_napi_get_typedarray_info>
256  ///
257  /// ***Warning***: Use caution while using this API since the underlying data buffer is managed by the VM.
258  pub fn into_value(self) -> Result<JsTypedArrayValue> {
259    let mut typedarray_type = 0;
260    let mut len = 0;
261    let mut data = ptr::null_mut();
262    let mut arraybuffer_value = ptr::null_mut();
263    let mut byte_offset = 0;
264    check_status!(unsafe {
265      sys::napi_get_typedarray_info(
266        self.0.env,
267        self.0.value,
268        &mut typedarray_type,
269        &mut len,
270        &mut data,
271        &mut arraybuffer_value,
272        &mut byte_offset,
273      )
274    })?;
275
276    Ok(JsTypedArrayValue {
277      data,
278      length: len,
279      byte_offset,
280      typedarray_type: typedarray_type.into(),
281      arraybuffer: unsafe { JsArrayBuffer::from_raw_unchecked(self.0.env, arraybuffer_value) },
282    })
283  }
284}
285
286impl JsTypedArrayValue {
287  #[inline]
288  fn is_valid_as_ref(&self, dest_type: TypedArrayType) {
289    // deref `Uint8ClampedArray` as `&[u8]` is valid
290    if self.typedarray_type == TypedArrayType::Uint8Clamped && dest_type == TypedArrayType::Uint8 {
291      return;
292    }
293    if self.typedarray_type != dest_type {
294      panic!(
295        "invalid typedarray type: expected {:?}, got {:?}",
296        dest_type, self.typedarray_type
297      );
298    }
299  }
300}
301
302macro_rules! impl_as_ref {
303  ($ref_type:ident, $expect_type:expr) => {
304    impl AsRef<[$ref_type]> for JsTypedArrayValue {
305      fn as_ref(&self) -> &[$ref_type] {
306        self.is_valid_as_ref($expect_type);
307        if self.data.is_null() {
308          return &[];
309        }
310        unsafe { slice::from_raw_parts(self.data as *const $ref_type, self.length) }
311      }
312    }
313
314    impl AsMut<[$ref_type]> for JsTypedArrayValue {
315      fn as_mut(&mut self) -> &mut [$ref_type] {
316        self.is_valid_as_ref($expect_type);
317        if self.data.is_null() {
318          return &mut [];
319        }
320        unsafe { slice::from_raw_parts_mut(self.data as *mut $ref_type, self.length) }
321      }
322    }
323  };
324}
325
326impl_as_ref!(u8, TypedArrayType::Uint8);
327impl_as_ref!(i8, TypedArrayType::Int8);
328impl_as_ref!(u16, TypedArrayType::Uint16);
329impl_as_ref!(i16, TypedArrayType::Int16);
330impl_as_ref!(u32, TypedArrayType::Uint32);
331impl_as_ref!(i32, TypedArrayType::Int32);
332impl_as_ref!(f32, TypedArrayType::Float32);
333impl_as_ref!(f64, TypedArrayType::Float64);
334#[cfg(feature = "napi6")]
335impl_as_ref!(i64, TypedArrayType::BigInt64);
336#[cfg(feature = "napi6")]
337impl_as_ref!(u64, TypedArrayType::BigUint64);
338
339impl JsDataView {
340  pub fn into_value(self) -> Result<JsDataViewValue> {
341    let mut length = 0u64;
342    let mut byte_offset = 0u64;
343    let mut arraybuffer_value = ptr::null_mut();
344    let mut data = ptr::null_mut();
345
346    check_status!(unsafe {
347      sys::napi_get_dataview_info(
348        self.0.env,
349        self.0.value,
350        &mut length as *mut u64 as *mut _,
351        &mut data,
352        &mut arraybuffer_value,
353        &mut byte_offset as *mut u64 as *mut _,
354      )
355    })?;
356    Ok(JsDataViewValue {
357      arraybuffer: unsafe { JsArrayBuffer::from_raw_unchecked(self.0.env, arraybuffer_value) },
358      byte_offset,
359      length,
360      _data: data,
361    })
362  }
363}