1 | use std::ops::{Deref, DerefMut}; |
2 | use std::os::raw::c_void; |
3 | use std::ptr; |
4 | use std::slice; |
5 | |
6 | use crate::bindgen_runtime::{TypeName, ValidateNapiValue}; |
7 | use crate::{ |
8 | check_status, sys, Error, JsUnknown, NapiValue, Ref, Result, Status, Value, ValueType, |
9 | }; |
10 | |
11 | pub struct JsArrayBuffer(pub(crate) Value); |
12 | |
13 | impl TypeName for JsArrayBuffer { |
14 | fn type_name() -> &'static str { |
15 | "ArrayBuffer" |
16 | } |
17 | |
18 | fn value_type() -> ValueType { |
19 | ValueType::Object |
20 | } |
21 | } |
22 | |
23 | impl 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 | |
37 | pub struct JsArrayBufferValue { |
38 | pub(crate) value: JsArrayBuffer, |
39 | len: usize, |
40 | data: *mut c_void, |
41 | } |
42 | |
43 | pub struct JsTypedArray(pub(crate) Value); |
44 | |
45 | impl TypeName for JsTypedArray { |
46 | fn type_name() -> &'static str { |
47 | "TypedArray" |
48 | } |
49 | |
50 | fn value_type() -> ValueType { |
51 | ValueType::Object |
52 | } |
53 | } |
54 | |
55 | pub 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 | |
63 | pub struct JsDataView(pub(crate) Value); |
64 | |
65 | impl TypeName for JsDataView { |
66 | fn type_name() -> &'static str { |
67 | "DataView" |
68 | } |
69 | |
70 | fn value_type() -> ValueType { |
71 | ValueType::Object |
72 | } |
73 | } |
74 | |
75 | pub 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 ] |
85 | pub 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 | |
104 | impl 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 | |
125 | impl From<TypedArrayType> for sys::napi_typedarray_type { |
126 | fn from(value: TypedArrayType) -> sys::napi_typedarray_type { |
127 | value as i32 |
128 | } |
129 | } |
130 | |
131 | impl 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 | |
206 | impl 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 | |
220 | impl AsRef<[u8]> for JsArrayBufferValue { |
221 | fn as_ref(&self) -> &[u8] { |
222 | unsafe { slice::from_raw_parts(self.data as *const u8, self.len) } |
223 | } |
224 | } |
225 | |
226 | impl AsMut<[u8]> for JsArrayBufferValue { |
227 | fn as_mut(&mut self) -> &mut [u8] { |
228 | unsafe { slice::from_raw_parts_mut(self.data as *mut u8, self.len) } |
229 | } |
230 | } |
231 | |
232 | impl Deref for JsArrayBufferValue { |
233 | type Target = [u8]; |
234 | |
235 | fn deref(&self) -> &Self::Target { |
236 | self.as_ref() |
237 | } |
238 | } |
239 | |
240 | impl DerefMut for JsArrayBufferValue { |
241 | fn deref_mut(&mut self) -> &mut Self::Target { |
242 | self.as_mut() |
243 | } |
244 | } |
245 | |
246 | impl JsTypedArray { |
247 | /// get TypeArray info |
248 | /// <https://nodejs.org/api/n-api.html#n_api_napi_get_typedarray_info> |
249 | /// |
250 | /// ***Warning***: Use caution while using this API since the underlying data buffer is managed by the VM. |
251 | pub fn into_value(self) -> Result<JsTypedArrayValue> { |
252 | let mut typedarray_type = 0; |
253 | let mut len = 0; |
254 | let mut data = ptr::null_mut(); |
255 | let mut arraybuffer_value = ptr::null_mut(); |
256 | let mut byte_offset = 0; |
257 | check_status!(unsafe { |
258 | sys::napi_get_typedarray_info( |
259 | self.0.env, |
260 | self.0.value, |
261 | &mut typedarray_type, |
262 | &mut len, |
263 | &mut data, |
264 | &mut arraybuffer_value, |
265 | &mut byte_offset, |
266 | ) |
267 | })?; |
268 | |
269 | Ok(JsTypedArrayValue { |
270 | data, |
271 | length: len, |
272 | byte_offset, |
273 | typedarray_type: typedarray_type.into(), |
274 | arraybuffer: unsafe { JsArrayBuffer::from_raw_unchecked(self.0.env, arraybuffer_value) }, |
275 | }) |
276 | } |
277 | } |
278 | |
279 | impl JsTypedArrayValue { |
280 | #[inline ] |
281 | fn is_valid_as_ref(&self, dest_type: TypedArrayType) { |
282 | // deref `Uint8ClampedArray` as `&[u8]` is valid |
283 | if self.typedarray_type == TypedArrayType::Uint8Clamped && dest_type == TypedArrayType::Uint8 { |
284 | return; |
285 | } |
286 | if self.typedarray_type != dest_type { |
287 | panic!( |
288 | "invalid typedarray type: expected {:?}, got {:?}" , |
289 | dest_type, self.typedarray_type |
290 | ); |
291 | } |
292 | } |
293 | } |
294 | |
295 | macro_rules! impl_as_ref { |
296 | ($ref_type:ident, $expect_type:expr) => { |
297 | impl AsRef<[$ref_type]> for JsTypedArrayValue { |
298 | fn as_ref(&self) -> &[$ref_type] { |
299 | self.is_valid_as_ref($expect_type); |
300 | unsafe { slice::from_raw_parts(self.data as *const $ref_type, self.length) } |
301 | } |
302 | } |
303 | |
304 | impl AsMut<[$ref_type]> for JsTypedArrayValue { |
305 | fn as_mut(&mut self) -> &mut [$ref_type] { |
306 | self.is_valid_as_ref($expect_type); |
307 | unsafe { slice::from_raw_parts_mut(self.data as *mut $ref_type, self.length) } |
308 | } |
309 | } |
310 | }; |
311 | } |
312 | |
313 | impl_as_ref!(u8, TypedArrayType::Uint8); |
314 | impl_as_ref!(i8, TypedArrayType::Int8); |
315 | impl_as_ref!(u16, TypedArrayType::Uint16); |
316 | impl_as_ref!(i16, TypedArrayType::Int16); |
317 | impl_as_ref!(u32, TypedArrayType::Uint32); |
318 | impl_as_ref!(i32, TypedArrayType::Int32); |
319 | impl_as_ref!(f32, TypedArrayType::Float32); |
320 | impl_as_ref!(f64, TypedArrayType::Float64); |
321 | #[cfg (feature = "napi6" )] |
322 | impl_as_ref!(i64, TypedArrayType::BigInt64); |
323 | #[cfg (feature = "napi6" )] |
324 | impl_as_ref!(u64, TypedArrayType::BigUint64); |
325 | |
326 | impl JsDataView { |
327 | pub fn into_value(self) -> Result<JsDataViewValue> { |
328 | let mut length = 0u64; |
329 | let mut byte_offset = 0u64; |
330 | let mut arraybuffer_value = ptr::null_mut(); |
331 | let mut data = ptr::null_mut(); |
332 | |
333 | check_status!(unsafe { |
334 | sys::napi_get_dataview_info( |
335 | self.0.env, |
336 | self.0.value, |
337 | &mut length as *mut u64 as *mut _, |
338 | &mut data, |
339 | &mut arraybuffer_value, |
340 | &mut byte_offset as *mut u64 as *mut _, |
341 | ) |
342 | })?; |
343 | Ok(JsDataViewValue { |
344 | arraybuffer: unsafe { JsArrayBuffer::from_raw_unchecked(self.0.env, arraybuffer_value) }, |
345 | byte_offset, |
346 | length, |
347 | _data: data, |
348 | }) |
349 | } |
350 | } |
351 | |