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