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) && !self.data.is_null() { |
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 | self.as_ref() |
258 | } |
259 | } |
260 | |
261 | impl DerefMut for $name { |
262 | fn deref_mut(&mut self) -> &mut Self::Target { |
263 | self.as_mut() |
264 | } |
265 | } |
266 | |
267 | impl AsRef<[$rust_type]> for $name { |
268 | fn as_ref(&self) -> &[$rust_type] { |
269 | if self.data.is_null() { |
270 | return &[]; |
271 | } |
272 | |
273 | unsafe { std::slice::from_raw_parts(self.data, self.length) } |
274 | } |
275 | } |
276 | |
277 | impl AsMut<[$rust_type]> for $name { |
278 | fn as_mut(&mut self) -> &mut [$rust_type] { |
279 | if self.data.is_null() { |
280 | return &mut []; |
281 | } |
282 | |
283 | unsafe { std::slice::from_raw_parts_mut(self.data, self.length) } |
284 | } |
285 | } |
286 | |
287 | impl TypeName for $name { |
288 | fn type_name() -> &'static str { |
289 | concat!("TypedArray<" , stringify!($rust_type), ">" ) |
290 | } |
291 | |
292 | fn value_type() -> crate::ValueType { |
293 | crate::ValueType::Object |
294 | } |
295 | } |
296 | |
297 | impl ValidateNapiValue for $name { |
298 | unsafe fn validate( |
299 | env: sys::napi_env, |
300 | napi_val: sys::napi_value, |
301 | ) -> Result<crate::sys::napi_value> { |
302 | let mut is_typed_array = false; |
303 | check_status!( |
304 | unsafe { sys::napi_is_typedarray(env, napi_val, &mut is_typed_array) }, |
305 | "Failed to check if value is typed array" |
306 | )?; |
307 | if !is_typed_array { |
308 | return Err(Error::new( |
309 | Status::InvalidArg, |
310 | "Expected a TypedArray value" .to_owned(), |
311 | )); |
312 | } |
313 | Ok(ptr::null_mut()) |
314 | } |
315 | } |
316 | |
317 | impl FromNapiValue for $name { |
318 | unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> { |
319 | let mut typed_array_type = 0; |
320 | let mut length = 0; |
321 | let mut data = ptr::null_mut(); |
322 | let mut array_buffer = ptr::null_mut(); |
323 | let mut byte_offset = 0; |
324 | let mut ref_ = ptr::null_mut(); |
325 | check_status!( |
326 | unsafe { sys::napi_create_reference(env, napi_val, 1, &mut ref_) }, |
327 | "Failed to create reference from Buffer" |
328 | )?; |
329 | check_status!( |
330 | unsafe { |
331 | sys::napi_get_typedarray_info( |
332 | env, |
333 | napi_val, |
334 | &mut typed_array_type, |
335 | &mut length, |
336 | &mut data, |
337 | &mut array_buffer, |
338 | &mut byte_offset, |
339 | ) |
340 | }, |
341 | "Get TypedArray info failed" |
342 | )?; |
343 | if typed_array_type != $typed_array_type as i32 { |
344 | return Err(Error::new( |
345 | Status::InvalidArg, |
346 | format!("Expected $name, got {}" , typed_array_type), |
347 | )); |
348 | } |
349 | Ok($name { |
350 | data: data as *mut $rust_type, |
351 | length, |
352 | byte_offset, |
353 | raw: Some((ref_, env)), |
354 | drop_in_vm: Arc::new(AtomicBool::new(true)), |
355 | data_managed_type: DataManagedType::Vm, |
356 | finalizer_notify: Box::into_raw(Box::new(Self::noop_finalize)), |
357 | }) |
358 | } |
359 | } |
360 | |
361 | impl ToNapiValue for $name { |
362 | unsafe fn to_napi_value(env: sys::napi_env, mut val: Self) -> Result<sys::napi_value> { |
363 | if let Some((ref_, _)) = val.raw { |
364 | let mut napi_value = std::ptr::null_mut(); |
365 | check_status!( |
366 | unsafe { sys::napi_get_reference_value(env, ref_, &mut napi_value) }, |
367 | "Failed to get reference from ArrayBuffer" |
368 | )?; |
369 | // fast path for ArrayBuffer::drop |
370 | if Arc::strong_count(&val.drop_in_vm) == 1 { |
371 | check_status!( |
372 | unsafe { sys::napi_delete_reference(env, ref_) }, |
373 | "Failed to delete reference in ArrayBuffer::to_napi_value" |
374 | )?; |
375 | val.raw = Some((ptr::null_mut(), ptr::null_mut())); |
376 | } |
377 | return Ok(napi_value); |
378 | } |
379 | let mut arraybuffer_value = ptr::null_mut(); |
380 | let ratio = mem::size_of::<$rust_type>(); |
381 | let val_length = val.length; |
382 | let length = val_length * ratio; |
383 | let val_data = val.data; |
384 | val.drop_in_vm.store(true, Ordering::Release); |
385 | check_status!( |
386 | if length == 0 { |
387 | // Rust uses 0x1 as the data pointer for empty buffers, |
388 | // but NAPI/V8 only allows multiple buffers to have |
389 | // the same data pointer if it's 0x0. |
390 | unsafe { |
391 | sys::napi_create_arraybuffer(env, length, ptr::null_mut(), &mut arraybuffer_value) |
392 | } |
393 | } else { |
394 | let hint_ptr = Box::into_raw(Box::new(val)); |
395 | let status = unsafe { |
396 | sys::napi_create_external_arraybuffer( |
397 | env, |
398 | val_data.cast(), |
399 | length, |
400 | Some(finalizer::<$rust_type, $name>), |
401 | hint_ptr.cast(), |
402 | &mut arraybuffer_value, |
403 | ) |
404 | }; |
405 | if status == napi_sys::Status::napi_no_external_buffers_allowed { |
406 | let hint = unsafe { Box::from_raw(hint_ptr) }; |
407 | let mut underlying_data = ptr::null_mut(); |
408 | let status = unsafe { |
409 | sys::napi_create_arraybuffer( |
410 | env, |
411 | length, |
412 | &mut underlying_data, |
413 | &mut arraybuffer_value, |
414 | ) |
415 | }; |
416 | unsafe { std::ptr::copy_nonoverlapping(hint.data.cast(), underlying_data, length) }; |
417 | status |
418 | } else { |
419 | status |
420 | } |
421 | }, |
422 | "Create external arraybuffer failed" |
423 | )?; |
424 | let mut napi_val = ptr::null_mut(); |
425 | check_status!( |
426 | unsafe { |
427 | sys::napi_create_typedarray( |
428 | env, |
429 | $typed_array_type as i32, |
430 | val_length, |
431 | arraybuffer_value, |
432 | 0, |
433 | &mut napi_val, |
434 | ) |
435 | }, |
436 | "Create TypedArray failed" |
437 | )?; |
438 | Ok(napi_val) |
439 | } |
440 | } |
441 | |
442 | impl ToNapiValue for &mut $name { |
443 | unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> { |
444 | if let Some((ref_, _)) = val.raw { |
445 | let mut napi_value = std::ptr::null_mut(); |
446 | check_status!( |
447 | unsafe { sys::napi_get_reference_value(env, ref_, &mut napi_value) }, |
448 | "Failed to get reference from ArrayBuffer" |
449 | )?; |
450 | Ok(napi_value) |
451 | } else { |
452 | let cloned_value = $name { |
453 | drop_in_vm: val.drop_in_vm.clone(), |
454 | data: val.data, |
455 | length: val.length, |
456 | data_managed_type: val.data_managed_type, |
457 | finalizer_notify: Box::into_raw(Box::new($name::noop_finalize)), |
458 | raw: None, |
459 | byte_offset: val.byte_offset, |
460 | }; |
461 | unsafe { ToNapiValue::to_napi_value(env, cloned_value) } |
462 | } |
463 | } |
464 | } |
465 | }; |
466 | } |
467 | |
468 | macro_rules! impl_from_slice { |
469 | ($name:ident, $rust_type:ident, $typed_array_type:expr) => { |
470 | impl FromNapiValue for &mut [$rust_type] { |
471 | unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> { |
472 | let mut typed_array_type = 0; |
473 | let mut length = 0; |
474 | let mut data = ptr::null_mut(); |
475 | let mut array_buffer = ptr::null_mut(); |
476 | let mut byte_offset = 0; |
477 | check_status!( |
478 | unsafe { |
479 | sys::napi_get_typedarray_info( |
480 | env, |
481 | napi_val, |
482 | &mut typed_array_type, |
483 | &mut length, |
484 | &mut data, |
485 | &mut array_buffer, |
486 | &mut byte_offset, |
487 | ) |
488 | }, |
489 | "Get TypedArray info failed" |
490 | )?; |
491 | if typed_array_type != $typed_array_type as i32 { |
492 | return Err(Error::new( |
493 | Status::InvalidArg, |
494 | format!("Expected $name, got {}" , typed_array_type), |
495 | )); |
496 | } |
497 | Ok(if length == 0 { |
498 | &mut [] |
499 | } else { |
500 | unsafe { core::slice::from_raw_parts_mut(data as *mut $rust_type, length) } |
501 | }) |
502 | } |
503 | } |
504 | |
505 | impl FromNapiValue for &[$rust_type] { |
506 | unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> { |
507 | let mut typed_array_type = 0; |
508 | let mut length = 0; |
509 | let mut data = ptr::null_mut(); |
510 | let mut array_buffer = ptr::null_mut(); |
511 | let mut byte_offset = 0; |
512 | check_status!( |
513 | unsafe { |
514 | sys::napi_get_typedarray_info( |
515 | env, |
516 | napi_val, |
517 | &mut typed_array_type, |
518 | &mut length, |
519 | &mut data, |
520 | &mut array_buffer, |
521 | &mut byte_offset, |
522 | ) |
523 | }, |
524 | "Get TypedArray info failed" |
525 | )?; |
526 | if typed_array_type != $typed_array_type as i32 { |
527 | return Err(Error::new( |
528 | Status::InvalidArg, |
529 | format!("Expected $name, got {}" , typed_array_type), |
530 | )); |
531 | } |
532 | Ok(if length == 0 { |
533 | &[] |
534 | } else { |
535 | unsafe { core::slice::from_raw_parts_mut(data as *mut $rust_type, length) } |
536 | }) |
537 | } |
538 | } |
539 | |
540 | impl TypeName for &mut [$rust_type] { |
541 | fn type_name() -> &'static str { |
542 | concat!("TypedArray<" , stringify!($rust_type), ">" ) |
543 | } |
544 | |
545 | fn value_type() -> crate::ValueType { |
546 | crate::ValueType::Object |
547 | } |
548 | } |
549 | |
550 | impl TypeName for &[$rust_type] { |
551 | fn type_name() -> &'static str { |
552 | concat!("TypedArray<" , stringify!($rust_type), ">" ) |
553 | } |
554 | |
555 | fn value_type() -> crate::ValueType { |
556 | crate::ValueType::Object |
557 | } |
558 | } |
559 | |
560 | impl ValidateNapiValue for &[$rust_type] { |
561 | unsafe fn validate(env: sys::napi_env, napi_val: sys::napi_value) -> Result<sys::napi_value> { |
562 | let mut is_typed_array = false; |
563 | check_status!( |
564 | unsafe { sys::napi_is_typedarray(env, napi_val, &mut is_typed_array) }, |
565 | "Failed to validate napi typed array" |
566 | )?; |
567 | if !is_typed_array { |
568 | return Err(Error::new( |
569 | Status::InvalidArg, |
570 | "Expected a TypedArray value" .to_owned(), |
571 | )); |
572 | } |
573 | Ok(ptr::null_mut()) |
574 | } |
575 | } |
576 | |
577 | impl ValidateNapiValue for &mut [$rust_type] { |
578 | unsafe fn validate(env: sys::napi_env, napi_val: sys::napi_value) -> Result<sys::napi_value> { |
579 | let mut is_typed_array = false; |
580 | check_status!( |
581 | unsafe { sys::napi_is_typedarray(env, napi_val, &mut is_typed_array) }, |
582 | "Failed to validate napi typed array" |
583 | )?; |
584 | if !is_typed_array { |
585 | return Err(Error::new( |
586 | Status::InvalidArg, |
587 | "Expected a TypedArray value" .to_owned(), |
588 | )); |
589 | } |
590 | Ok(ptr::null_mut()) |
591 | } |
592 | } |
593 | }; |
594 | } |
595 | |
596 | unsafe extern "C" fn finalizer<Data, T: Finalizer<RustType = Data>>( |
597 | _env: sys::napi_env, |
598 | finalize_data: *mut c_void, |
599 | finalize_hint: *mut c_void, |
600 | ) { |
601 | let data: T = unsafe { *Box::from_raw(finalize_hint as *mut T) }; |
602 | let data_managed_type: DataManagedType = *data.data_managed_type(); |
603 | let length: usize = *data.len(); |
604 | match data_managed_type { |
605 | DataManagedType::Vm => { |
606 | // do nothing |
607 | } |
608 | DataManagedType::Owned => { |
609 | if data.ref_count() == 1 { |
610 | unsafe { Vec::from_raw_parts(ptr:finalize_data as *mut Data, length, capacity:length) }; |
611 | } |
612 | } |
613 | DataManagedType::External => { |
614 | if data.ref_count() == 1 { |
615 | let finalizer_notify: Box = unsafe { Box::from_raw(data.finalizer_notify()) }; |
616 | (finalizer_notify)(finalize_data as *mut Data, length); |
617 | } |
618 | } |
619 | } |
620 | } |
621 | |
622 | #[derive (PartialEq, Eq, Clone, Copy)] |
623 | enum DataManagedType { |
624 | /// Vm managed data, passed in from JavaScript |
625 | Vm, |
626 | /// Rust owned data, which need to be deallocated in the finalizer |
627 | Owned, |
628 | /// External data, which need to be notice to the owner in finalizer |
629 | External, |
630 | } |
631 | |
632 | impl_typed_array!(Int8Array, i8, TypedArrayType::Int8); |
633 | impl_from_slice!(Int8Array, i8, TypedArrayType::Int8); |
634 | impl_typed_array!(Uint8Array, u8, TypedArrayType::Uint8); |
635 | impl_from_slice!(Uint8Array, u8, TypedArrayType::Uint8); |
636 | impl_typed_array!(Uint8ClampedArray, u8, TypedArrayType::Uint8Clamped); |
637 | impl_typed_array!(Int16Array, i16, TypedArrayType::Int16); |
638 | impl_from_slice!(Int16Array, i16, TypedArrayType::Int16); |
639 | impl_typed_array!(Uint16Array, u16, TypedArrayType::Uint16); |
640 | impl_from_slice!(Uint16Array, u16, TypedArrayType::Uint16); |
641 | impl_typed_array!(Int32Array, i32, TypedArrayType::Int32); |
642 | impl_from_slice!(Int32Array, i32, TypedArrayType::Int32); |
643 | impl_typed_array!(Uint32Array, u32, TypedArrayType::Uint32); |
644 | impl_from_slice!(Uint32Array, u32, TypedArrayType::Uint32); |
645 | impl_typed_array!(Float32Array, f32, TypedArrayType::Float32); |
646 | impl_from_slice!(Float32Array, f32, TypedArrayType::Float32); |
647 | impl_typed_array!(Float64Array, f64, TypedArrayType::Float64); |
648 | impl_from_slice!(Float64Array, f64, TypedArrayType::Float64); |
649 | #[cfg (feature = "napi6" )] |
650 | impl_typed_array!(BigInt64Array, i64, TypedArrayType::BigInt64); |
651 | #[cfg (feature = "napi6" )] |
652 | impl_from_slice!(BigInt64Array, i64, TypedArrayType::BigInt64); |
653 | #[cfg (feature = "napi6" )] |
654 | impl_typed_array!(BigUint64Array, u64, TypedArrayType::BigUint64); |
655 | #[cfg (feature = "napi6" )] |
656 | impl_from_slice!(BigUint64Array, u64, TypedArrayType::BigUint64); |
657 | |
658 | /// Zero copy Uint8ClampedArray slice shared between Rust and Node.js. |
659 | /// It can only be used in non-async context and the lifetime is bound to the fn closure. |
660 | /// If you want to use Node.js `Uint8ClampedArray` in async context or want to extend the lifetime, use `Uint8ClampedArray` instead. |
661 | pub struct Uint8ClampedSlice<'scope> { |
662 | pub(crate) inner: &'scope mut [u8], |
663 | raw_value: sys::napi_value, |
664 | } |
665 | |
666 | impl<'scope> FromNapiValue for Uint8ClampedSlice<'scope> { |
667 | unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> { |
668 | let mut typed_array_type = 0; |
669 | let mut length = 0; |
670 | let mut data = ptr::null_mut(); |
671 | let mut array_buffer = ptr::null_mut(); |
672 | let mut byte_offset = 0; |
673 | check_status!( |
674 | unsafe { |
675 | sys::napi_get_typedarray_info( |
676 | env, |
677 | napi_val, |
678 | &mut typed_array_type, |
679 | &mut length, |
680 | &mut data, |
681 | &mut array_buffer, |
682 | &mut byte_offset, |
683 | ) |
684 | }, |
685 | "Get TypedArray info failed" |
686 | )?; |
687 | if typed_array_type != TypedArrayType::Uint8Clamped as i32 { |
688 | return Err(Error::new( |
689 | Status::InvalidArg, |
690 | format!("Expected $name, got {}" , typed_array_type), |
691 | )); |
692 | } |
693 | Ok(Self { |
694 | inner: if length == 0 { |
695 | &mut [] |
696 | } else { |
697 | unsafe { core::slice::from_raw_parts_mut(data.cast(), length) } |
698 | }, |
699 | raw_value: napi_val, |
700 | }) |
701 | } |
702 | } |
703 | |
704 | impl ToNapiValue for Uint8ClampedSlice<'_> { |
705 | #[allow (unused_variables)] |
706 | unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> { |
707 | Ok(val.raw_value) |
708 | } |
709 | } |
710 | |
711 | impl TypeName for Uint8ClampedSlice<'_> { |
712 | fn type_name() -> &'static str { |
713 | "Uint8ClampedArray" |
714 | } |
715 | |
716 | fn value_type() -> ValueType { |
717 | ValueType::Object |
718 | } |
719 | } |
720 | |
721 | impl ValidateNapiValue for Uint8ClampedSlice<'_> { |
722 | unsafe fn validate(env: sys::napi_env, napi_val: sys::napi_value) -> Result<sys::napi_value> { |
723 | let mut is_typedarray: bool = false; |
724 | check_status!( |
725 | unsafe { sys::napi_is_typedarray(env, napi_val, &mut is_typedarray) }, |
726 | "Failed to validate typed buffer" |
727 | )?; |
728 | if !is_typedarray { |
729 | return Err(Error::new( |
730 | Status::InvalidArg, |
731 | reason:"Expected a TypedArray value" .to_owned(), |
732 | )); |
733 | } |
734 | Ok(ptr::null_mut()) |
735 | } |
736 | } |
737 | |
738 | impl AsRef<[u8]> for Uint8ClampedSlice<'_> { |
739 | fn as_ref(&self) -> &[u8] { |
740 | self.inner |
741 | } |
742 | } |
743 | |
744 | impl<'scope> Deref for Uint8ClampedSlice<'scope> { |
745 | type Target = [u8]; |
746 | |
747 | fn deref(&self) -> &Self::Target { |
748 | self.inner |
749 | } |
750 | } |
751 | |
752 | impl<'scope> DerefMut for Uint8ClampedSlice<'scope> { |
753 | fn deref_mut(&mut self) -> &mut Self::Target { |
754 | self.inner |
755 | } |
756 | } |
757 | |
758 | impl<T: Into<Vec<u8>>> From<T> for Uint8Array { |
759 | fn from(data: T) -> Self { |
760 | Uint8Array::new(data.into()) |
761 | } |
762 | } |
763 | |
764 | impl<T: Into<Vec<u8>>> From<T> for Uint8ClampedArray { |
765 | fn from(data: T) -> Self { |
766 | Uint8ClampedArray::new(data.into()) |
767 | } |
768 | } |
769 | |
770 | impl<T: Into<Vec<u16>>> From<T> for Uint16Array { |
771 | fn from(data: T) -> Self { |
772 | Uint16Array::new(data.into()) |
773 | } |
774 | } |
775 | |
776 | impl<T: Into<Vec<u32>>> From<T> for Uint32Array { |
777 | fn from(data: T) -> Self { |
778 | Uint32Array::new(data.into()) |
779 | } |
780 | } |
781 | |
782 | impl<T: Into<Vec<i8>>> From<T> for Int8Array { |
783 | fn from(data: T) -> Self { |
784 | Int8Array::new(data.into()) |
785 | } |
786 | } |
787 | |
788 | impl<T: Into<Vec<i16>>> From<T> for Int16Array { |
789 | fn from(data: T) -> Self { |
790 | Int16Array::new(data.into()) |
791 | } |
792 | } |
793 | |
794 | impl<T: Into<Vec<i32>>> From<T> for Int32Array { |
795 | fn from(data: T) -> Self { |
796 | Int32Array::new(data.into()) |
797 | } |
798 | } |
799 | |
800 | impl<T: Into<Vec<f32>>> From<T> for Float32Array { |
801 | fn from(data: T) -> Self { |
802 | Float32Array::new(data.into()) |
803 | } |
804 | } |
805 | |
806 | impl<T: Into<Vec<f64>>> From<T> for Float64Array { |
807 | fn from(data: T) -> Self { |
808 | Float64Array::new(data.into()) |
809 | } |
810 | } |
811 | |
812 | #[cfg (feature = "napi6" )] |
813 | impl<T: Into<Vec<i64>>> From<T> for BigInt64Array { |
814 | fn from(data: T) -> Self { |
815 | BigInt64Array::new(data.into()) |
816 | } |
817 | } |
818 | #[cfg (feature = "napi6" )] |
819 | impl<T: Into<Vec<u64>>> From<T> for BigUint64Array { |
820 | fn from(data: T) -> Self { |
821 | BigUint64Array::new(data.into()) |
822 | } |
823 | } |
824 | |