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