1 | use std::ffi::c_void; |
2 | use std::mem; |
3 | use std::ops::{Deref, DerefMut}; |
4 | use std::ptr; |
5 | use std::sync::{ |
6 | atomic::{AtomicBool, Ordering}, |
7 | Arc, |
8 | }; |
9 | |
10 | #[cfg (all(feature = "napi4" , not(feature = "noop" ), not(target_family = "wasm" )))] |
11 | use crate::bindgen_prelude::{CUSTOM_GC_TSFN, CUSTOM_GC_TSFN_DESTROYED, THREADS_CAN_ACCESS_ENV}; |
12 | pub use crate::js_values::TypedArrayType; |
13 | use crate::{check_status, sys, Error, Result, Status, ValueType}; |
14 | |
15 | use super::{FromNapiValue, ToNapiValue, TypeName, ValidateNapiValue}; |
16 | |
17 | #[cfg (target_family = "wasm" )] |
18 | extern "C" { |
19 | fn emnapi_sync_memory( |
20 | env: crate::sys::napi_env, |
21 | js_to_wasm: bool, |
22 | arraybuffer_or_view: crate::sys::napi_value, |
23 | byte_offset: usize, |
24 | length: usize, |
25 | ) -> crate::sys::napi_status; |
26 | } |
27 | |
28 | trait Finalizer { |
29 | type RustType; |
30 | |
31 | fn finalizer_notify(&self) -> *mut dyn FnOnce(*mut Self::RustType, usize); |
32 | |
33 | fn data_managed_type(&self) -> &DataManagedType; |
34 | |
35 | fn len(&self) -> &usize; |
36 | |
37 | fn ref_count(&self) -> usize; |
38 | } |
39 | |
40 | macro_rules! impl_typed_array { |
41 | ($name:ident, $rust_type:ident, $typed_array_type:expr) => { |
42 | pub struct $name { |
43 | data: *mut $rust_type, |
44 | length: usize, |
45 | data_managed_type: DataManagedType, |
46 | byte_offset: usize, |
47 | raw: Option<(crate::sys::napi_ref, crate::sys::napi_env)>, |
48 | // Use `Arc` for ref count |
49 | // Use `AtomicBool` for flag to indicate whether the value is dropped in VM |
50 | drop_in_vm: Arc<AtomicBool>, |
51 | finalizer_notify: *mut dyn FnOnce(*mut $rust_type, usize), |
52 | } |
53 | |
54 | unsafe impl Send for $name {} |
55 | |
56 | impl Finalizer for $name { |
57 | type RustType = $rust_type; |
58 | |
59 | fn finalizer_notify(&self) -> *mut dyn FnOnce(*mut Self::RustType, usize) { |
60 | self.finalizer_notify |
61 | } |
62 | |
63 | fn data_managed_type(&self) -> &DataManagedType { |
64 | &self.data_managed_type |
65 | } |
66 | |
67 | fn len(&self) -> &usize { |
68 | &self.length |
69 | } |
70 | |
71 | fn ref_count(&self) -> usize { |
72 | Arc::strong_count(&self.drop_in_vm) |
73 | } |
74 | } |
75 | |
76 | impl Drop for $name { |
77 | fn drop(&mut self) { |
78 | if Arc::strong_count(&self.drop_in_vm) == 1 { |
79 | if let Some((ref_, env)) = self.raw { |
80 | if ref_.is_null() { |
81 | return; |
82 | } |
83 | #[cfg(all(feature = "napi4" , not(feature = "noop" ), not(target_family = "wasm" )))] |
84 | { |
85 | if CUSTOM_GC_TSFN_DESTROYED.load(Ordering::SeqCst) { |
86 | return; |
87 | } |
88 | if !THREADS_CAN_ACCESS_ENV |
89 | .borrow_mut(|m| m.get(&std::thread::current().id()).is_some()) |
90 | { |
91 | let status = unsafe { |
92 | sys::napi_call_threadsafe_function( |
93 | CUSTOM_GC_TSFN.load(std::sync::atomic::Ordering::SeqCst), |
94 | ref_.cast(), |
95 | 1, |
96 | ) |
97 | }; |
98 | assert!( |
99 | status == sys::Status::napi_ok || status == sys::Status::napi_closing, |
100 | "Call custom GC in ArrayBuffer::drop failed {}" , |
101 | Status::from(status) |
102 | ); |
103 | return; |
104 | } |
105 | } |
106 | let mut ref_count = 0; |
107 | crate::check_status_or_throw!( |
108 | env, |
109 | unsafe { sys::napi_reference_unref(env, ref_, &mut ref_count) }, |
110 | "Failed to unref ArrayBuffer reference in drop" |
111 | ); |
112 | debug_assert!( |
113 | ref_count == 0, |
114 | "ArrayBuffer reference count in ArrayBuffer::drop is not zero" |
115 | ); |
116 | crate::check_status_or_throw!( |
117 | env, |
118 | unsafe { sys::napi_delete_reference(env, ref_) }, |
119 | "Failed to delete ArrayBuffer reference in drop" |
120 | ); |
121 | return; |
122 | } |
123 | if !self.drop_in_vm.load(Ordering::Acquire) { |
124 | match &self.data_managed_type { |
125 | DataManagedType::Owned => { |
126 | let length = self.length; |
127 | unsafe { Vec::from_raw_parts(self.data, length, length) }; |
128 | } |
129 | DataManagedType::External => { |
130 | let finalizer = unsafe { Box::from_raw(self.finalizer_notify) }; |
131 | (finalizer)(self.data, self.length); |
132 | } |
133 | _ => {} |
134 | } |
135 | } |
136 | } |
137 | } |
138 | } |
139 | |
140 | impl $name { |
141 | fn noop_finalize(_data: *mut $rust_type, _length: usize) {} |
142 | |
143 | #[cfg(target_family = "wasm" )] |
144 | pub fn sync(&mut self, env: &crate::Env) { |
145 | if let Some((reference, _)) = self.raw { |
146 | let mut value = ptr::null_mut(); |
147 | let mut array_buffer = ptr::null_mut(); |
148 | crate::check_status_or_throw!( |
149 | env.raw(), |
150 | unsafe { crate::sys::napi_get_reference_value(env.raw(), reference, &mut value) }, |
151 | "Failed to get reference value from TypedArray while syncing" |
152 | ); |
153 | crate::check_status_or_throw!( |
154 | env.raw(), |
155 | unsafe { |
156 | crate::sys::napi_get_typedarray_info( |
157 | env.raw(), |
158 | value, |
159 | &mut ($typed_array_type as i32) as *mut i32, |
160 | &mut self.length as *mut usize, |
161 | ptr::null_mut(), |
162 | &mut array_buffer, |
163 | &mut self.byte_offset as *mut usize, |
164 | ) |
165 | }, |
166 | "Failed to get ArrayBuffer under the TypedArray while syncing" |
167 | ); |
168 | crate::check_status_or_throw!( |
169 | env.raw(), |
170 | unsafe { |
171 | emnapi_sync_memory( |
172 | env.raw(), |
173 | false, |
174 | array_buffer, |
175 | self.byte_offset, |
176 | self.length, |
177 | ) |
178 | }, |
179 | "Failed to sync memory" |
180 | ); |
181 | } else { |
182 | return; |
183 | } |
184 | } |
185 | |
186 | pub fn new(mut data: Vec<$rust_type>) -> Self { |
187 | data.shrink_to_fit(); |
188 | let ret = $name { |
189 | data: data.as_mut_ptr(), |
190 | length: data.len(), |
191 | data_managed_type: DataManagedType::Owned, |
192 | byte_offset: 0, |
193 | raw: None, |
194 | drop_in_vm: Arc::new(AtomicBool::new(false)), |
195 | finalizer_notify: Box::into_raw(Box::new(Self::noop_finalize)), |
196 | }; |
197 | mem::forget(data); |
198 | ret |
199 | } |
200 | |
201 | pub fn with_data_copied<D>(data: D) -> Self |
202 | where |
203 | D: AsRef<[$rust_type]>, |
204 | { |
205 | let mut data_copied = data.as_ref().to_vec(); |
206 | let ret = $name { |
207 | data: data_copied.as_mut_ptr(), |
208 | length: data.as_ref().len(), |
209 | data_managed_type: DataManagedType::Owned, |
210 | finalizer_notify: Box::into_raw(Box::new(Self::noop_finalize)), |
211 | raw: None, |
212 | drop_in_vm: Arc::new(AtomicBool::new(false)), |
213 | byte_offset: 0, |
214 | }; |
215 | mem::forget(data_copied); |
216 | ret |
217 | } |
218 | |
219 | /// # Safety |
220 | /// |
221 | /// The caller will be notified when the data is deallocated by vm |
222 | pub unsafe fn with_external_data<F>(data: *mut $rust_type, length: usize, notify: F) -> Self |
223 | where |
224 | F: 'static + FnOnce(*mut $rust_type, usize), |
225 | { |
226 | $name { |
227 | data, |
228 | length, |
229 | data_managed_type: DataManagedType::External, |
230 | finalizer_notify: Box::into_raw(Box::new(notify)), |
231 | raw: None, |
232 | drop_in_vm: Arc::new(AtomicBool::new(false)), |
233 | byte_offset: 0, |
234 | } |
235 | } |
236 | } |
237 | |
238 | impl Clone for $name { |
239 | /// Clone reference, the inner data is not copied nor moved |
240 | fn clone(&self) -> $name { |
241 | Self { |
242 | data: self.data, |
243 | length: self.length, |
244 | data_managed_type: self.data_managed_type, |
245 | finalizer_notify: self.finalizer_notify, |
246 | raw: self.raw, |
247 | drop_in_vm: self.drop_in_vm.clone(), |
248 | byte_offset: self.byte_offset, |
249 | } |
250 | } |
251 | } |
252 | |
253 | impl Deref for $name { |
254 | type Target = [$rust_type]; |
255 | |
256 | fn deref(&self) -> &Self::Target { |
257 | unsafe { std::slice::from_raw_parts(self.data, self.length) } |
258 | } |
259 | } |
260 | |
261 | impl DerefMut for $name { |
262 | fn deref_mut(&mut self) -> &mut Self::Target { |
263 | unsafe { std::slice::from_raw_parts_mut(self.data, self.length) } |
264 | } |
265 | } |
266 | |
267 | impl AsRef<[$rust_type]> for $name { |
268 | fn as_ref(&self) -> &[$rust_type] { |
269 | unsafe { std::slice::from_raw_parts(self.data, self.length) } |
270 | } |
271 | } |
272 | |
273 | impl AsMut<[$rust_type]> for $name { |
274 | fn as_mut(&mut self) -> &mut [$rust_type] { |
275 | unsafe { std::slice::from_raw_parts_mut(self.data, self.length) } |
276 | } |
277 | } |
278 | |
279 | impl TypeName for $name { |
280 | fn type_name() -> &'static str { |
281 | concat!("TypedArray<" , stringify!($rust_type), ">" ) |
282 | } |
283 | |
284 | fn value_type() -> crate::ValueType { |
285 | crate::ValueType::Object |
286 | } |
287 | } |
288 | |
289 | impl ValidateNapiValue for $name { |
290 | unsafe fn validate( |
291 | env: sys::napi_env, |
292 | napi_val: sys::napi_value, |
293 | ) -> Result<crate::sys::napi_value> { |
294 | let mut is_typed_array = false; |
295 | check_status!( |
296 | unsafe { sys::napi_is_typedarray(env, napi_val, &mut is_typed_array) }, |
297 | "Failed to check if value is typed array" |
298 | )?; |
299 | if !is_typed_array { |
300 | return Err(Error::new( |
301 | Status::InvalidArg, |
302 | "Expected a TypedArray value" .to_owned(), |
303 | )); |
304 | } |
305 | Ok(ptr::null_mut()) |
306 | } |
307 | } |
308 | |
309 | impl FromNapiValue for $name { |
310 | unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> { |
311 | let mut typed_array_type = 0; |
312 | let mut length = 0; |
313 | let mut data = ptr::null_mut(); |
314 | let mut array_buffer = ptr::null_mut(); |
315 | let mut byte_offset = 0; |
316 | let mut ref_ = ptr::null_mut(); |
317 | check_status!( |
318 | unsafe { sys::napi_create_reference(env, napi_val, 1, &mut ref_) }, |
319 | "Failed to create reference from Buffer" |
320 | )?; |
321 | check_status!( |
322 | unsafe { |
323 | sys::napi_get_typedarray_info( |
324 | env, |
325 | napi_val, |
326 | &mut typed_array_type, |
327 | &mut length, |
328 | &mut data, |
329 | &mut array_buffer, |
330 | &mut byte_offset, |
331 | ) |
332 | }, |
333 | "Get TypedArray info failed" |
334 | )?; |
335 | if typed_array_type != $typed_array_type as i32 { |
336 | return Err(Error::new( |
337 | Status::InvalidArg, |
338 | format!("Expected $name, got {}" , typed_array_type), |
339 | )); |
340 | } |
341 | Ok($name { |
342 | data: data as *mut $rust_type, |
343 | length, |
344 | byte_offset, |
345 | raw: Some((ref_, env)), |
346 | drop_in_vm: Arc::new(AtomicBool::new(true)), |
347 | data_managed_type: DataManagedType::Vm, |
348 | finalizer_notify: Box::into_raw(Box::new(Self::noop_finalize)), |
349 | }) |
350 | } |
351 | } |
352 | |
353 | impl ToNapiValue for $name { |
354 | unsafe fn to_napi_value(env: sys::napi_env, mut val: Self) -> Result<sys::napi_value> { |
355 | if let Some((ref_, _)) = val.raw { |
356 | let mut napi_value = std::ptr::null_mut(); |
357 | check_status!( |
358 | unsafe { sys::napi_get_reference_value(env, ref_, &mut napi_value) }, |
359 | "Failed to get reference from ArrayBuffer" |
360 | )?; |
361 | // fast path for ArrayBuffer::drop |
362 | if Arc::strong_count(&val.drop_in_vm) == 1 { |
363 | check_status!( |
364 | unsafe { sys::napi_delete_reference(env, ref_) }, |
365 | "Failed to delete reference in ArrayBuffer::to_napi_value" |
366 | )?; |
367 | val.raw = Some((ptr::null_mut(), ptr::null_mut())); |
368 | } |
369 | return Ok(napi_value); |
370 | } |
371 | let mut arraybuffer_value = ptr::null_mut(); |
372 | let ratio = mem::size_of::<$rust_type>(); |
373 | let val_length = val.length; |
374 | let length = val_length * ratio; |
375 | let val_data = val.data; |
376 | val.drop_in_vm.store(true, Ordering::Release); |
377 | check_status!( |
378 | if length == 0 { |
379 | // Rust uses 0x1 as the data pointer for empty buffers, |
380 | // but NAPI/V8 only allows multiple buffers to have |
381 | // the same data pointer if it's 0x0. |
382 | unsafe { |
383 | sys::napi_create_arraybuffer(env, length, ptr::null_mut(), &mut arraybuffer_value) |
384 | } |
385 | } else { |
386 | let hint_ptr = Box::into_raw(Box::new(val)); |
387 | let status = unsafe { |
388 | sys::napi_create_external_arraybuffer( |
389 | env, |
390 | val_data.cast(), |
391 | length, |
392 | Some(finalizer::<$rust_type, $name>), |
393 | hint_ptr.cast(), |
394 | &mut arraybuffer_value, |
395 | ) |
396 | }; |
397 | if status == napi_sys::Status::napi_no_external_buffers_allowed { |
398 | let hint = unsafe { Box::from_raw(hint_ptr) }; |
399 | let mut underlying_data = ptr::null_mut(); |
400 | let status = unsafe { |
401 | sys::napi_create_arraybuffer( |
402 | env, |
403 | length, |
404 | &mut underlying_data, |
405 | &mut arraybuffer_value, |
406 | ) |
407 | }; |
408 | unsafe { std::ptr::copy_nonoverlapping(hint.data.cast(), underlying_data, length) }; |
409 | status |
410 | } else { |
411 | status |
412 | } |
413 | }, |
414 | "Create external arraybuffer failed" |
415 | )?; |
416 | let mut napi_val = ptr::null_mut(); |
417 | check_status!( |
418 | unsafe { |
419 | sys::napi_create_typedarray( |
420 | env, |
421 | $typed_array_type as i32, |
422 | val_length, |
423 | arraybuffer_value, |
424 | 0, |
425 | &mut napi_val, |
426 | ) |
427 | }, |
428 | "Create TypedArray failed" |
429 | )?; |
430 | Ok(napi_val) |
431 | } |
432 | } |
433 | |
434 | impl ToNapiValue for &mut $name { |
435 | unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> { |
436 | if let Some((ref_, _)) = val.raw { |
437 | let mut napi_value = std::ptr::null_mut(); |
438 | check_status!( |
439 | unsafe { sys::napi_get_reference_value(env, ref_, &mut napi_value) }, |
440 | "Failed to get reference from ArrayBuffer" |
441 | )?; |
442 | Ok(napi_value) |
443 | } else { |
444 | let cloned_value = $name { |
445 | drop_in_vm: val.drop_in_vm.clone(), |
446 | data: val.data, |
447 | length: val.length, |
448 | data_managed_type: val.data_managed_type, |
449 | finalizer_notify: Box::into_raw(Box::new($name::noop_finalize)), |
450 | raw: None, |
451 | byte_offset: val.byte_offset, |
452 | }; |
453 | unsafe { ToNapiValue::to_napi_value(env, cloned_value) } |
454 | } |
455 | } |
456 | } |
457 | }; |
458 | } |
459 | |
460 | macro_rules! impl_from_slice { |
461 | ($name:ident, $rust_type:ident, $typed_array_type:expr) => { |
462 | impl FromNapiValue for &mut [$rust_type] { |
463 | unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> { |
464 | let mut typed_array_type = 0; |
465 | let mut length = 0; |
466 | let mut data = ptr::null_mut(); |
467 | let mut array_buffer = ptr::null_mut(); |
468 | let mut byte_offset = 0; |
469 | check_status!( |
470 | unsafe { |
471 | sys::napi_get_typedarray_info( |
472 | env, |
473 | napi_val, |
474 | &mut typed_array_type, |
475 | &mut length, |
476 | &mut data, |
477 | &mut array_buffer, |
478 | &mut byte_offset, |
479 | ) |
480 | }, |
481 | "Get TypedArray info failed" |
482 | )?; |
483 | if typed_array_type != $typed_array_type as i32 { |
484 | return Err(Error::new( |
485 | Status::InvalidArg, |
486 | format!("Expected $name, got {}" , typed_array_type), |
487 | )); |
488 | } |
489 | Ok(if length == 0 { |
490 | &mut [] |
491 | } else { |
492 | unsafe { core::slice::from_raw_parts_mut(data as *mut $rust_type, length) } |
493 | }) |
494 | } |
495 | } |
496 | |
497 | impl FromNapiValue for &[$rust_type] { |
498 | unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> { |
499 | let mut typed_array_type = 0; |
500 | let mut length = 0; |
501 | let mut data = ptr::null_mut(); |
502 | let mut array_buffer = ptr::null_mut(); |
503 | let mut byte_offset = 0; |
504 | check_status!( |
505 | unsafe { |
506 | sys::napi_get_typedarray_info( |
507 | env, |
508 | napi_val, |
509 | &mut typed_array_type, |
510 | &mut length, |
511 | &mut data, |
512 | &mut array_buffer, |
513 | &mut byte_offset, |
514 | ) |
515 | }, |
516 | "Get TypedArray info failed" |
517 | )?; |
518 | if typed_array_type != $typed_array_type as i32 { |
519 | return Err(Error::new( |
520 | Status::InvalidArg, |
521 | format!("Expected $name, got {}" , typed_array_type), |
522 | )); |
523 | } |
524 | Ok(if length == 0 { |
525 | &[] |
526 | } else { |
527 | unsafe { core::slice::from_raw_parts_mut(data as *mut $rust_type, length) } |
528 | }) |
529 | } |
530 | } |
531 | |
532 | impl TypeName for &mut [$rust_type] { |
533 | fn type_name() -> &'static str { |
534 | concat!("TypedArray<" , stringify!($rust_type), ">" ) |
535 | } |
536 | |
537 | fn value_type() -> crate::ValueType { |
538 | crate::ValueType::Object |
539 | } |
540 | } |
541 | |
542 | impl TypeName for &[$rust_type] { |
543 | fn type_name() -> &'static str { |
544 | concat!("TypedArray<" , stringify!($rust_type), ">" ) |
545 | } |
546 | |
547 | fn value_type() -> crate::ValueType { |
548 | crate::ValueType::Object |
549 | } |
550 | } |
551 | |
552 | impl ValidateNapiValue for &[$rust_type] { |
553 | unsafe fn validate(env: sys::napi_env, napi_val: sys::napi_value) -> Result<sys::napi_value> { |
554 | let mut is_typed_array = false; |
555 | check_status!( |
556 | unsafe { sys::napi_is_typedarray(env, napi_val, &mut is_typed_array) }, |
557 | "Failed to validate napi typed array" |
558 | )?; |
559 | if !is_typed_array { |
560 | return Err(Error::new( |
561 | Status::InvalidArg, |
562 | "Expected a TypedArray value" .to_owned(), |
563 | )); |
564 | } |
565 | Ok(ptr::null_mut()) |
566 | } |
567 | } |
568 | |
569 | impl ValidateNapiValue for &mut [$rust_type] { |
570 | unsafe fn validate(env: sys::napi_env, napi_val: sys::napi_value) -> Result<sys::napi_value> { |
571 | let mut is_typed_array = false; |
572 | check_status!( |
573 | unsafe { sys::napi_is_typedarray(env, napi_val, &mut is_typed_array) }, |
574 | "Failed to validate napi typed array" |
575 | )?; |
576 | if !is_typed_array { |
577 | return Err(Error::new( |
578 | Status::InvalidArg, |
579 | "Expected a TypedArray value" .to_owned(), |
580 | )); |
581 | } |
582 | Ok(ptr::null_mut()) |
583 | } |
584 | } |
585 | }; |
586 | } |
587 | |
588 | unsafe extern "C" fn finalizer<Data, T: Finalizer<RustType = Data>>( |
589 | _env: sys::napi_env, |
590 | finalize_data: *mut c_void, |
591 | finalize_hint: *mut c_void, |
592 | ) { |
593 | let data: T = unsafe { *Box::from_raw(finalize_hint as *mut T) }; |
594 | let data_managed_type: DataManagedType = *data.data_managed_type(); |
595 | let length: usize = *data.len(); |
596 | match data_managed_type { |
597 | DataManagedType::Vm => { |
598 | // do nothing |
599 | } |
600 | DataManagedType::Owned => { |
601 | if data.ref_count() == 1 { |
602 | unsafe { Vec::from_raw_parts(ptr:finalize_data as *mut Data, length, capacity:length) }; |
603 | } |
604 | } |
605 | DataManagedType::External => { |
606 | if data.ref_count() == 1 { |
607 | let finalizer_notify: Box = unsafe { Box::from_raw(data.finalizer_notify()) }; |
608 | (finalizer_notify)(finalize_data as *mut Data, length); |
609 | } |
610 | } |
611 | } |
612 | } |
613 | |
614 | #[derive (PartialEq, Eq, Clone, Copy)] |
615 | enum DataManagedType { |
616 | /// Vm managed data, passed in from JavaScript |
617 | Vm, |
618 | /// Rust owned data, which need to be deallocated in the finalizer |
619 | Owned, |
620 | /// External data, which need to be notice to the owner in finalizer |
621 | External, |
622 | } |
623 | |
624 | impl_typed_array!(Int8Array, i8, TypedArrayType::Int8); |
625 | impl_from_slice!(Int8Array, i8, TypedArrayType::Int8); |
626 | impl_typed_array!(Uint8Array, u8, TypedArrayType::Uint8); |
627 | impl_from_slice!(Uint8Array, u8, TypedArrayType::Uint8); |
628 | impl_typed_array!(Uint8ClampedArray, u8, TypedArrayType::Uint8Clamped); |
629 | impl_typed_array!(Int16Array, i16, TypedArrayType::Int16); |
630 | impl_from_slice!(Int16Array, i16, TypedArrayType::Int16); |
631 | impl_typed_array!(Uint16Array, u16, TypedArrayType::Uint16); |
632 | impl_from_slice!(Uint16Array, u16, TypedArrayType::Uint16); |
633 | impl_typed_array!(Int32Array, i32, TypedArrayType::Int32); |
634 | impl_from_slice!(Int32Array, i32, TypedArrayType::Int32); |
635 | impl_typed_array!(Uint32Array, u32, TypedArrayType::Uint32); |
636 | impl_from_slice!(Uint32Array, u32, TypedArrayType::Uint32); |
637 | impl_typed_array!(Float32Array, f32, TypedArrayType::Float32); |
638 | impl_from_slice!(Float32Array, f32, TypedArrayType::Float32); |
639 | impl_typed_array!(Float64Array, f64, TypedArrayType::Float64); |
640 | impl_from_slice!(Float64Array, f64, TypedArrayType::Float64); |
641 | #[cfg (feature = "napi6" )] |
642 | impl_typed_array!(BigInt64Array, i64, TypedArrayType::BigInt64); |
643 | #[cfg (feature = "napi6" )] |
644 | impl_from_slice!(BigInt64Array, i64, TypedArrayType::BigInt64); |
645 | #[cfg (feature = "napi6" )] |
646 | impl_typed_array!(BigUint64Array, u64, TypedArrayType::BigUint64); |
647 | #[cfg (feature = "napi6" )] |
648 | impl_from_slice!(BigUint64Array, u64, TypedArrayType::BigUint64); |
649 | |
650 | /// Zero copy Uint8ClampedArray slice shared between Rust and Node.js. |
651 | /// It can only be used in non-async context and the lifetime is bound to the fn closure. |
652 | /// If you want to use Node.js `Uint8ClampedArray` in async context or want to extend the lifetime, use `Uint8ClampedArray` instead. |
653 | pub struct Uint8ClampedSlice<'scope> { |
654 | pub(crate) inner: &'scope mut [u8], |
655 | raw_value: sys::napi_value, |
656 | } |
657 | |
658 | impl<'scope> FromNapiValue for Uint8ClampedSlice<'scope> { |
659 | unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> { |
660 | let mut typed_array_type = 0; |
661 | let mut length = 0; |
662 | let mut data = ptr::null_mut(); |
663 | let mut array_buffer = ptr::null_mut(); |
664 | let mut byte_offset = 0; |
665 | check_status!( |
666 | unsafe { |
667 | sys::napi_get_typedarray_info( |
668 | env, |
669 | napi_val, |
670 | &mut typed_array_type, |
671 | &mut length, |
672 | &mut data, |
673 | &mut array_buffer, |
674 | &mut byte_offset, |
675 | ) |
676 | }, |
677 | "Get TypedArray info failed" |
678 | )?; |
679 | if typed_array_type != TypedArrayType::Uint8Clamped as i32 { |
680 | return Err(Error::new( |
681 | Status::InvalidArg, |
682 | format!("Expected $name, got {}" , typed_array_type), |
683 | )); |
684 | } |
685 | Ok(Self { |
686 | inner: if length == 0 { |
687 | &mut [] |
688 | } else { |
689 | unsafe { core::slice::from_raw_parts_mut(data.cast(), length) } |
690 | }, |
691 | raw_value: napi_val, |
692 | }) |
693 | } |
694 | } |
695 | |
696 | impl ToNapiValue for Uint8ClampedSlice<'_> { |
697 | #[allow (unused_variables)] |
698 | unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> { |
699 | Ok(val.raw_value) |
700 | } |
701 | } |
702 | |
703 | impl TypeName for Uint8ClampedSlice<'_> { |
704 | fn type_name() -> &'static str { |
705 | "Uint8ClampedArray" |
706 | } |
707 | |
708 | fn value_type() -> ValueType { |
709 | ValueType::Object |
710 | } |
711 | } |
712 | |
713 | impl ValidateNapiValue for Uint8ClampedSlice<'_> { |
714 | unsafe fn validate(env: sys::napi_env, napi_val: sys::napi_value) -> Result<sys::napi_value> { |
715 | let mut is_typedarray: bool = false; |
716 | check_status!( |
717 | unsafe { sys::napi_is_typedarray(env, napi_val, &mut is_typedarray) }, |
718 | "Failed to validate typed buffer" |
719 | )?; |
720 | if !is_typedarray { |
721 | return Err(Error::new( |
722 | Status::InvalidArg, |
723 | reason:"Expected a TypedArray value" .to_owned(), |
724 | )); |
725 | } |
726 | Ok(ptr::null_mut()) |
727 | } |
728 | } |
729 | |
730 | impl AsRef<[u8]> for Uint8ClampedSlice<'_> { |
731 | fn as_ref(&self) -> &[u8] { |
732 | self.inner |
733 | } |
734 | } |
735 | |
736 | impl<'scope> Deref for Uint8ClampedSlice<'scope> { |
737 | type Target = [u8]; |
738 | |
739 | fn deref(&self) -> &Self::Target { |
740 | self.inner |
741 | } |
742 | } |
743 | |
744 | impl<'scope> DerefMut for Uint8ClampedSlice<'scope> { |
745 | fn deref_mut(&mut self) -> &mut Self::Target { |
746 | self.inner |
747 | } |
748 | } |
749 | |
750 | impl<T: Into<Vec<u8>>> From<T> for Uint8Array { |
751 | fn from(data: T) -> Self { |
752 | Uint8Array::new(data:data.into()) |
753 | } |
754 | } |
755 | |
756 | impl<T: Into<Vec<u8>>> From<T> for Uint8ClampedArray { |
757 | fn from(data: T) -> Self { |
758 | Uint8ClampedArray::new(data:data.into()) |
759 | } |
760 | } |
761 | |
762 | impl<T: Into<Vec<u16>>> From<T> for Uint16Array { |
763 | fn from(data: T) -> Self { |
764 | Uint16Array::new(data:data.into()) |
765 | } |
766 | } |
767 | |
768 | impl<T: Into<Vec<u32>>> From<T> for Uint32Array { |
769 | fn from(data: T) -> Self { |
770 | Uint32Array::new(data:data.into()) |
771 | } |
772 | } |
773 | |
774 | impl<T: Into<Vec<i8>>> From<T> for Int8Array { |
775 | fn from(data: T) -> Self { |
776 | Int8Array::new(data:data.into()) |
777 | } |
778 | } |
779 | |
780 | impl<T: Into<Vec<i16>>> From<T> for Int16Array { |
781 | fn from(data: T) -> Self { |
782 | Int16Array::new(data:data.into()) |
783 | } |
784 | } |
785 | |
786 | impl<T: Into<Vec<i32>>> From<T> for Int32Array { |
787 | fn from(data: T) -> Self { |
788 | Int32Array::new(data:data.into()) |
789 | } |
790 | } |
791 | |
792 | impl<T: Into<Vec<f32>>> From<T> for Float32Array { |
793 | fn from(data: T) -> Self { |
794 | Float32Array::new(data:data.into()) |
795 | } |
796 | } |
797 | |
798 | impl<T: Into<Vec<f64>>> From<T> for Float64Array { |
799 | fn from(data: T) -> Self { |
800 | Float64Array::new(data:data.into()) |
801 | } |
802 | } |
803 | |
804 | #[cfg (feature = "napi6" )] |
805 | impl<T: Into<Vec<i64>>> From<T> for BigInt64Array { |
806 | fn from(data: T) -> Self { |
807 | BigInt64Array::new(data:data.into()) |
808 | } |
809 | } |
810 | #[cfg (feature = "napi6" )] |
811 | impl<T: Into<Vec<u64>>> From<T> for BigUint64Array { |
812 | fn from(data: T) -> Self { |
813 | BigUint64Array::new(data:data.into()) |
814 | } |
815 | } |
816 | |