Skip to content
File

Blob: src/rust/jsg/wrappable.rs

rust757 lines
1// Copyright (c) 2026 Cloudflare, Inc.
2// Licensed under the Apache 2.0 license found in the LICENSE file or at:
3// https://opensource.org/licenses/Apache-2.0
4 
5#![allow(clippy::allow_attributes)]
6 
7//! Traits for converting between Rust and JavaScript values.
8//!
9//! # Supported Types
10//!
11//! ## Primitive Types
12//!
13//! | Rust Type | JavaScript Type |
14//! |-----------|-----------------|
15//! | `()` | `undefined` |
16//! | `String` | `string` |
17//! | `&str` | `string` |
18//! | `bool` | `boolean` |
19//! | `Number` | `number` |
20//! | `Option<T>` | `T` or `undefined` |
21//! | `Nullable<T>` | `T`, `null`, or `undefined` |
22//! | `Result<T, E>` | `T` or throws |
23//! | `NonCoercible<T>` | `T` (strict type checking) |
24//! | `T: Struct` | `object` |
25//! | `Vec<T>` | `Array<T>` |
26//! | `&[T]` | `Array<T>` (parameter only) |
27//!
28//! ## `TypedArray` Types
29//!
30//! These specialized `Vec` and slice types map directly to JavaScript `TypedArray`s
31//! for efficient binary data transfer:
32//!
33//! | Rust Type | JavaScript Type |
34//! |-----------|-----------------|
35//! | `Vec<u8>` | `Uint8Array` |
36//! | `Vec<u16>` | `Uint16Array` |
37//! | `Vec<u32>` | `Uint32Array` |
38//! | `Vec<i8>` | `Int8Array` |
39//! | `Vec<i16>` | `Int16Array` |
40//! | `Vec<i32>` | `Int32Array` |
41//! | `Vec<f32>` | `Float32Array` |
42//! | `Vec<f64>` | `Float64Array` |
43//! | `Vec<i64>` | `BigInt64Array` |
44//! | `Vec<u64>` | `BigUint64Array` |
45//! | `&[u8]` | `Uint8Array` (parameter only) |
46//! | `&[u16]` | `Uint16Array` (parameter only) |
47//! | `&[u32]` | `Uint32Array` (parameter only) |
48//! | `&[i8]` | `Int8Array` (parameter only) |
49//! | `&[i16]` | `Int16Array` (parameter only) |
50//! | `&[i32]` | `Int32Array` (parameter only) |
51//! | `&[f32]` | `Float32Array` (parameter only) |
52//! | `&[f64]` | `Float64Array` (parameter only) |
53//! | `&[i64]` | `BigInt64Array` (parameter only) |
54//! | `&[u64]` | `BigUint64Array` (parameter only) |
55//!
56//! ## Integer Parameter Types
57//!
58//! Integer types (`u8`, `u16`, `u32`, `i8`, `i16`, `i32`) can be used as method
59//! parameters. JavaScript numbers are converted via truncation:
60//!
61//! - Values are truncated toward zero (e.g., `3.7` → `3`, `-2.9` → `-2`)
62//! - Out-of-range values wrap (e.g., `256.0` → `0` for `u8`)
63//! - `NaN` becomes `0`
64//!
65//! For strict validation, wrap parameters in `NonCoercible<T>` or validate manually.
66 
67use crate::Error;
68use crate::Lock;
69use crate::NonCoercible;
70use crate::Nullable;
71use crate::Number;
72use crate::Type;
73use crate::v8;
74use crate::v8::ToLocalValue;
75 
76// =============================================================================
77// Traced trait — GC tracing for field types
78// =============================================================================
79 
80/// Trait for types that can be visited during V8 garbage collection tracing.
81///
82/// Every type that can appear as a field in a `#[jsg_resource]` struct must
83/// implement `Traced`. The generated `Traced::trace` body calls
84/// `Traced::trace` on every field — types with no GC-visible references
85/// simply use the default no-op implementation.
86///
87/// # Built-in implementations
88///
89/// - **Primitives** (`bool`, `String`, integers, floats, `()`) — no-op.
90/// - **`Option<T>`**, **`Nullable<T>`** — delegates to the inner value if present.
91/// - **Collections** (`Vec<T>`, `HashMap<K,V>`, `BTreeMap<K,V>`, `HashSet<T>`,
92/// `BTreeSet<T>`) — iterates elements/values and traces each.
93/// - **`Cell<T>`** — reads through `as_ptr()` (sound under single-threaded GC).
94/// - **`jsg::Rc<T>`** — visits the reference via `GcVisitor::visit_rc`.
95/// - **`jsg::Weak<T>`** — no-op (weak refs don't keep targets alive).
96/// - **`jsg::v8::Global<T>`** — visits via `GcVisitor::visit_global`.
97pub trait Traced {
98 /// Visit GC-visible references held by this value.
99 ///
100 /// The default implementation is a no-op, suitable for types with no
101 /// GC-visible references (primitives, plain data structs, etc.).
102 fn trace(&self, _visitor: &mut crate::v8::GcVisitor) {}
103}
104 
105/// Generates no-op `Traced` implementations for types with no GC-visible references.
106macro_rules! impl_traced_noop {
107 ($($t:ty),* $(,)?) => {
108 $(impl Traced for $t {})*
109 };
110}
111 
112impl_traced_noop!(
113 (),
114 bool,
115 String,
116 crate::Error,
117 u8,
118 u16,
119 u32,
120 u64,
121 usize,
122 i8,
123 i16,
124 i32,
125 i64,
126 isize,
127 f32,
128 f64,
129 crate::v8::ArrayBuffer,
130 crate::v8::ArrayBufferView,
131 crate::v8::BackingStore,
132 crate::v8::BigInt64Array,
133 crate::v8::BigUint64Array,
134 crate::v8::Float32Array,
135 crate::v8::Float64Array,
136 crate::v8::Int8Array,
137 crate::v8::Int16Array,
138 crate::v8::Int32Array,
139 crate::v8::Uint8Array,
140 crate::v8::Uint16Array,
141 crate::v8::Uint32Array,
142 &str,
143 Number,
144);
145 
146impl<T: Traced> Traced for Option<T> {
147 fn trace(&self, visitor: &mut crate::v8::GcVisitor) {
148 if let Some(inner) = self {
149 inner.trace(visitor);
150 }
151 }
152}
153 
154impl<T: Traced> Traced for Nullable<T> {
155 fn trace(&self, visitor: &mut crate::v8::GcVisitor) {
156 if let Self::Some(inner) = self {
157 inner.trace(visitor);
158 }
159 }
160}
161 
162impl<T: Traced> Traced for NonCoercible<T> {
163 fn trace(&self, visitor: &mut crate::v8::GcVisitor) {
164 self.as_ref().trace(visitor);
165 }
166}
167 
168impl<T: Traced> Traced for Vec<T> {
169 fn trace(&self, visitor: &mut crate::v8::GcVisitor) {
170 for item in self {
171 item.trace(visitor);
172 }
173 }
174}
175 
176impl<K, V: Traced, S: std::hash::BuildHasher> Traced for std::collections::HashMap<K, V, S> {
177 fn trace(&self, visitor: &mut crate::v8::GcVisitor) {
178 for value in self.values() {
179 value.trace(visitor);
180 }
181 }
182}
183 
184impl<K, V: Traced> Traced for std::collections::BTreeMap<K, V> {
185 fn trace(&self, visitor: &mut crate::v8::GcVisitor) {
186 for value in self.values() {
187 value.trace(visitor);
188 }
189 }
190}
191 
192impl<T: Traced, S: std::hash::BuildHasher> Traced for std::collections::HashSet<T, S> {
193 fn trace(&self, visitor: &mut crate::v8::GcVisitor) {
194 for item in self {
195 item.trace(visitor);
196 }
197 }
198}
199 
200impl<T: Traced> Traced for std::collections::BTreeSet<T> {
201 fn trace(&self, visitor: &mut crate::v8::GcVisitor) {
202 for item in self {
203 item.trace(visitor);
204 }
205 }
206}
207 
208impl<T: Traced> Traced for std::cell::Cell<T> {
209 fn trace(&self, visitor: &mut crate::v8::GcVisitor) {
210 // SAFETY: V8 GC tracing is single-threaded within an isolate and never
211 // re-entrant on the same object during a single GC cycle. We only read
212 // through the pointer.
213 unsafe {
214 (*self.as_ptr()).trace(visitor);
215 }
216 }
217}
218 
219impl<T: Traced> Traced for std::cell::RefCell<T> {
220 fn trace(&self, visitor: &mut crate::v8::GcVisitor) {
221 // Use `try_borrow()` to avoid panicking across the FFI boundary if a
222 // mutable borrow is active during GC.
223 if let Ok(inner) = self.try_borrow() {
224 inner.trace(visitor);
225 }
226 }
227}
228 
229impl<T: Traced> Traced for std::rc::Rc<T> {
230 fn trace(&self, visitor: &mut crate::v8::GcVisitor) {
231 (**self).trace(visitor);
232 }
233}
234 
235// =============================================================================
236// ToJS trait (Rust → JavaScript)
237// =============================================================================
238 
239/// Trait for converting Rust values to JavaScript.
240///
241/// Provides Rust → JavaScript conversion.
242pub trait ToJS: Sized {
243 /// Converts this Rust value into a JavaScript value.
244 fn to_js<'a, 'b>(self, lock: &'a mut Lock) -> v8::Local<'b, v8::Value>
245 where
246 'b: 'a;
247}
248 
249// =============================================================================
250// FromJS trait (JavaScript → Rust)
251// =============================================================================
252 
253/// Trait for converting JavaScript values to Rust.
254///
255/// Provides JS → Rust conversion. The `try_unwrap` method is used by macros
256/// to unwrap function parameters with proper error handling.
257pub trait FromJS: Sized {
258 type ResultType;
259 
260 /// Converts a JavaScript value into this Rust type.
261 fn from_js(lock: &mut Lock, value: v8::Local<v8::Value>) -> Result<Self::ResultType, Error>;
262 
263 /// Tries to convert only if the JavaScript type matches exactly.
264 /// Returns `None` if the type doesn't match, `Some(result)` if conversion was attempted.
265 /// Used by `#[jsg_oneof]` macro to try each variant without coercion.
266 fn try_from_js_exact(
267 lock: &mut Lock,
268 value: &v8::Local<v8::Value>,
269 ) -> Option<Result<Self::ResultType, Error>>
270 where
271 Self: Type,
272 {
273 if Self::is_exact(value) {
274 Some(Self::from_js(lock, value.clone()))
275 } else {
276 None
277 }
278 }
279}
280 
281// =============================================================================
282// Primitive type implementations
283// =============================================================================
284 
285/// Implements `Type`, `ToJS`, and `FromJS` for primitive types.
286macro_rules! impl_primitive {
287 { $type:ty, $class_name:literal, $is_exact:ident, $unwrap_fn:ident } => {
288 impl Type for $type {
289 fn class_name() -> &'static str {
290 $class_name
291 }
292 
293 fn is_exact(value: &v8::Local<v8::Value>) -> bool {
294 value.$is_exact()
295 }
296 }
297 
298 impl ToJS for $type {
299 fn to_js<'a, 'b>(self, lock: &'a mut Lock) -> v8::Local<'b, v8::Value>
300 where
301 'b: 'a,
302 {
303 self.to_local(lock)
304 }
305 }
306 
307 impl FromJS for $type {
308 type ResultType = Self;
309 
310 fn from_js(lock: &mut Lock, value: v8::Local<v8::Value>) -> Result<Self::ResultType, Error> {
311 // SAFETY: The isolate is locked and value is a valid V8 local handle.
312 Ok(unsafe { v8::ffi::$unwrap_fn(lock.isolate().as_ffi(), value.into_ffi()) })
313 }
314 }
315 };
316}
317 
318impl_primitive!(std::string::String, "string", is_string, unwrap_string);
319impl_primitive!(bool, "boolean", is_boolean, unwrap_boolean);
320 
321// Number implementation for JavaScript numbers
322impl Type for Number {
323 fn class_name() -> &'static str {
324 "number"
325 }
326 
327 fn is_exact(value: &v8::Local<v8::Value>) -> bool {
328 value.is_number()
329 }
330}
331 
332impl ToJS for Number {
333 fn to_js<'a, 'b>(self, lock: &'a mut Lock) -> v8::Local<'b, v8::Value>
334 where
335 'b: 'a,
336 {
337 self.to_local(lock)
338 }
339}
340 
341impl FromJS for Number {
342 type ResultType = Self;
343 
344 fn from_js(lock: &mut Lock, value: v8::Local<v8::Value>) -> Result<Self::ResultType, Error> {
345 // SAFETY: The isolate is locked and value is a valid V8 local handle.
346 let f64_value =
347 unsafe { v8::ffi::unwrap_number(lock.isolate().as_ffi(), value.into_ffi()) };
348 Ok(Self::new(f64_value))
349 }
350}
351 
352// Special implementation for &str - allows functions to accept &str parameters
353// by converting JavaScript strings to owned Strings, then borrowing.
354// The macro handles passing &arg instead of arg for reference types.
355impl Type for &str {
356 fn class_name() -> &'static str {
357 "string"
358 }
359 
360 fn is_exact(value: &v8::Local<v8::Value>) -> bool {
361 value.is_string()
362 }
363}
364 
365impl FromJS for &str {
366 type ResultType = String;
367 
368 fn from_js(lock: &mut Lock, value: v8::Local<v8::Value>) -> Result<Self::ResultType, Error> {
369 // SAFETY: The isolate is locked and value is a valid V8 local handle.
370 Ok(unsafe { v8::ffi::unwrap_string(lock.isolate().as_ffi(), value.into_ffi()) })
371 }
372}
373 
374impl<T: FromJS<ResultType = T>> FromJS for &T {
375 type ResultType = T;
376 
377 fn from_js(lock: &mut Lock, value: v8::Local<v8::Value>) -> Result<Self::ResultType, Error> {
378 T::from_js(lock, value)
379 }
380}
381 
382// Slice type - allows functions to accept &[T] parameters.
383// JavaScript arrays are converted to Vec<T>, then borrowed as &[T] by the macro.
384impl<T: Type> Type for &[T] {
385 fn class_name() -> &'static str {
386 "Array"
387 }
388 
389 fn is_exact(value: &v8::Local<v8::Value>) -> bool {
390 value.is_array()
391 }
392}
393 
394impl<T: Type + FromJS<ResultType = T>> FromJS for &[T] {
395 type ResultType = Vec<T>;
396 
397 fn from_js(lock: &mut Lock, value: v8::Local<v8::Value>) -> Result<Self::ResultType, Error> {
398 Vec::<T>::from_js(lock, value)
399 }
400}
401 
402// Integer types - JavaScript numbers are IEEE 754 doubles (f64)
403//
404// Conversion behavior:
405// - Values are truncated toward zero (e.g., 3.7 → 3, -2.9 → -2)
406// - Values outside the target type's range wrap around (e.g., 256.0 → 0 for u8)
407// - NaN becomes 0
408// - Infinity wraps to 0 for unsigned types, or type MIN/MAX for signed types
409//
410// This matches JavaScript's behavior for TypedArray element assignment.
411// For strict validation, use `NonCoercible<T>` or validate in your method.
412macro_rules! impl_integer_from_js {
413 ($($type:ty),*) => {
414 $(
415 impl FromJS for $type {
416 type ResultType = Self;
417 
418 #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
419 fn from_js(lock: &mut Lock, value: v8::Local<v8::Value>) -> Result<Self::ResultType, Error> {
420 // SAFETY: The isolate is locked and value is a valid V8 local handle.
421 let num = unsafe { v8::ffi::unwrap_number(lock.isolate().as_ffi(), value.into_ffi()) };
422 Ok(num as $type)
423 }
424 }
425 )*
426 };
427}
428 
429impl_integer_from_js!(u8, u16, u32, i8, i16, i32);
430 
431// =============================================================================
432// Wrapper type implementations
433// =============================================================================
434 
435impl ToJS for () {
436 fn to_js<'a, 'b>(self, lock: &'a mut Lock) -> v8::Local<'b, v8::Value>
437 where
438 'b: 'a,
439 {
440 v8::Local::<v8::Value>::undefined(lock)
441 }
442}
443 
444impl<T: ToJS> ToJS for Option<T> {
445 fn to_js<'a, 'b>(self, lock: &'a mut Lock) -> v8::Local<'b, v8::Value>
446 where
447 'b: 'a,
448 {
449 match self {
450 Some(value) => value.to_js(lock),
451 None => v8::Local::<v8::Value>::undefined(lock),
452 }
453 }
454}
455 
456impl<T: Type + ToJS> ToJS for NonCoercible<T> {
457 fn to_js<'a, 'b>(self, lock: &'a mut Lock) -> v8::Local<'b, v8::Value>
458 where
459 'b: 'a,
460 {
461 self.into_inner().to_js(lock)
462 }
463}
464 
465impl<T: ToJS> ToJS for Nullable<T> {
466 fn to_js<'a, 'b>(self, lock: &'a mut Lock) -> v8::Local<'b, v8::Value>
467 where
468 'b: 'a,
469 {
470 match self {
471 Self::Some(value) => value.to_js(lock),
472 Self::Null => v8::Local::<v8::Value>::null(lock),
473 Self::Undefined => v8::Local::<v8::Value>::undefined(lock),
474 }
475 }
476}
477 
478impl<T: Type + FromJS> FromJS for Option<T> {
479 type ResultType = Option<T::ResultType>;
480 
481 fn from_js(lock: &mut Lock, value: v8::Local<v8::Value>) -> Result<Self::ResultType, Error> {
482 if value.is_null() {
483 let msg = format!("Expected {} or undefined but got null", T::class_name());
484 Err(Error::new_type_error(msg))
485 } else if value.is_undefined() {
486 Ok(None)
487 } else {
488 Ok(Some(T::from_js(lock, value)?))
489 }
490 }
491}
492 
493impl<T: Type + FromJS> FromJS for NonCoercible<T> {
494 type ResultType = NonCoercible<T::ResultType>;
495 
496 fn from_js(lock: &mut Lock, value: v8::Local<v8::Value>) -> Result<Self::ResultType, Error> {
497 if !T::is_exact(&value) {
498 let error_msg = format!(
499 "Expected a {} value but got {}",
500 T::class_name(),
501 value.type_of()
502 );
503 return Err(Error::new_type_error(error_msg));
504 }
505 Ok(<Self::ResultType>::new(T::from_js(lock, value)?))
506 }
507}
508 
509impl<T: Type + FromJS> FromJS for Nullable<T> {
510 type ResultType = Nullable<T::ResultType>;
511 
512 fn from_js(lock: &mut Lock, value: v8::Local<v8::Value>) -> Result<Self::ResultType, Error> {
513 if value.is_null() {
514 Ok(Nullable::Null)
515 } else if value.is_undefined() {
516 Ok(Nullable::Undefined)
517 } else {
518 Ok(Nullable::Some(T::from_js(lock, value)?))
519 }
520 }
521}
522 
523// =============================================================================
524// Array type implementations (Vec<T>)
525// =============================================================================
526 
527impl<T: Type> Type for Vec<T> {
528 fn class_name() -> &'static str {
529 "Array"
530 }
531 
532 fn is_exact(value: &v8::Local<v8::Value>) -> bool {
533 value.is_array()
534 }
535}
536 
537impl<T: ToJS> ToJS for Vec<T> {
538 fn to_js<'a, 'b>(self, lock: &'a mut Lock) -> v8::Local<'b, v8::Value>
539 where
540 'b: 'a,
541 {
542 let mut array = v8::Array::new(lock, self.len());
543 for (i, item) in self.into_iter().enumerate() {
544 array.set(i, item.to_js(lock));
545 }
546 array.into()
547 }
548}
549 
550impl<T: Type + FromJS<ResultType = T>> FromJS for Vec<T> {
551 type ResultType = Self;
552 
553 fn from_js(lock: &mut Lock, value: v8::Local<v8::Value>) -> Result<Self::ResultType, Error> {
554 let type_name = value.type_of();
555 let array = value
556 .try_as::<v8::Array>()
557 .ok_or_else(|| Error::new_type_error(format!("Expected Array but got {type_name}")))?;
558 
559 let globals = array.iterate();
560 let mut result = Self::with_capacity(globals.len());
561 for global in globals {
562 let local = global.as_local(lock);
563 result.push(T::from_js(lock, local)?);
564 }
565 Ok(result)
566 }
567}
568 
569// =============================================================================
570// TypedArray implementations
571// =============================================================================
572//
573// This macro generates implementations for TypedArray types:
574// - `v8::*Array` marker types: `Type` trait for type-safe V8 handles
575// - `Vec<T>`: `Type`, `ToJS`, `FromJS` for bidirectional conversion
576// - `&[T]`: `Type`, `FromJS` for parameter-only conversion (delegates to Vec<T>)
577//
578// Supported mappings:
579// - `Vec<u8>` / `&[u8]` <-> `Uint8Array`
580// - `Vec<u16>` / `&[u16]` <-> `Uint16Array`
581// - `Vec<u32>` / `&[u32]` <-> `Uint32Array`
582// - `Vec<i8>` / `&[i8]` <-> `Int8Array`
583// - `Vec<i16>` / `&[i16]` <-> `Int16Array`
584// - `Vec<i32>` / `&[i32]` <-> `Int32Array`
585// - `Vec<f32>` / `&[f32]` <-> `Float32Array`
586// - `Vec<f64>` / `&[f64]` <-> `Float64Array`
587// - `Vec<i64>` / `&[i64]` <-> `BigInt64Array`
588// - `Vec<u64>` / `&[u64]` <-> `BigUint64Array`
589 
590macro_rules! impl_typed_array {
591 ($elem:ty, $marker:ident, $is_check:ident, $new_fn:ident, $unwrap_fn:ident) => {
592 impl Type for v8::$marker {
593 fn class_name() -> &'static str {
594 stringify!($marker)
595 }
596 fn is_exact(value: &v8::Local<v8::Value>) -> bool {
597 value.$is_check()
598 }
599 }
600 
601 impl Type for Vec<$elem> {
602 fn class_name() -> &'static str {
603 stringify!($marker)
604 }
605 fn is_exact(value: &v8::Local<v8::Value>) -> bool {
606 value.$is_check()
607 }
608 }
609 
610 impl Type for &[$elem] {
611 fn class_name() -> &'static str {
612 stringify!($marker)
613 }
614 fn is_exact(value: &v8::Local<v8::Value>) -> bool {
615 value.$is_check()
616 }
617 }
618 
619 impl ToJS for Vec<$elem> {
620 fn to_js<'a, 'b>(self, lock: &'a mut Lock) -> v8::Local<'b, v8::Value>
621 where
622 'b: 'a,
623 {
624 let isolate = lock.isolate();
625 // SAFETY: Lock guarantees the isolate is locked and a HandleScope is active.
626 unsafe {
627 v8::Local::from_ffi(
628 isolate,
629 v8::ffi::$new_fn(isolate.as_ffi(), self.as_ptr(), self.len()),
630 )
631 }
632 }
633 }
634 
635 impl FromJS for Vec<$elem> {
636 type ResultType = Self;
637 
638 fn from_js(lock: &mut Lock, value: v8::Local<v8::Value>) -> Result<Self, Error> {
639 if !value.$is_check() {
640 return Err(Error::new_type_error(format!(
641 "Expected {} but got {}",
642 stringify!($marker),
643 value.type_of()
644 )));
645 }
646 // SAFETY: The isolate is locked and value is a valid V8 local handle of the correct TypedArray type.
647 Ok(unsafe { v8::ffi::$unwrap_fn(lock.isolate().as_ffi(), value.into_ffi()) })
648 }
649 }
650 
651 impl FromJS for &[$elem] {
652 type ResultType = Vec<$elem>;
653 
654 fn from_js(lock: &mut Lock, value: v8::Local<v8::Value>) -> Result<Vec<$elem>, Error> {
655 Vec::<$elem>::from_js(lock, value)
656 }
657 }
658 };
659}
660 
661impl_typed_array!(
662 u8,
663 Uint8Array,
664 is_uint8_array,
665 local_new_uint8_array,
666 unwrap_uint8_array
667);
668impl_typed_array!(
669 u16,
670 Uint16Array,
671 is_uint16_array,
672 local_new_uint16_array,
673 unwrap_uint16_array
674);
675impl_typed_array!(
676 u32,
677 Uint32Array,
678 is_uint32_array,
679 local_new_uint32_array,
680 unwrap_uint32_array
681);
682impl_typed_array!(
683 i8,
684 Int8Array,
685 is_int8_array,
686 local_new_int8_array,
687 unwrap_int8_array
688);
689impl_typed_array!(
690 i16,
691 Int16Array,
692 is_int16_array,
693 local_new_int16_array,
694 unwrap_int16_array
695);
696impl_typed_array!(
697 i32,
698 Int32Array,
699 is_int32_array,
700 local_new_int32_array,
701 unwrap_int32_array
702);
703impl_typed_array!(
704 f32,
705 Float32Array,
706 is_float32_array,
707 local_new_float32_array,
708 unwrap_float32_array
709);
710impl_typed_array!(
711 f64,
712 Float64Array,
713 is_float64_array,
714 local_new_float64_array,
715 unwrap_float64_array
716);
717impl_typed_array!(
718 i64,
719 BigInt64Array,
720 is_bigint64_array,
721 local_new_bigint64_array,
722 unwrap_bigint64_array
723);
724impl_typed_array!(
725 u64,
726 BigUint64Array,
727 is_biguint64_array,
728 local_new_biguint64_array,
729 unwrap_biguint64_array
730);
731 
732// =============================================================================
733// ArrayBuffer, ArrayBufferView, SharedArrayBuffer
734// =============================================================================
735//
736// These three types only implement `Type` (used by `NonCoercible<T>` for type
737// checking). They do not have element-typed `ToJS`/`FromJS` conversions and
738// do not fit the `impl_typed_array!` macro.
739 
740impl Type for v8::ArrayBuffer {
741 fn class_name() -> &'static str {
742 "ArrayBuffer"
743 }
744 fn is_exact(value: &v8::Local<v8::Value>) -> bool {
745 value.is_array_buffer()
746 }
747}
748 
749impl Type for v8::ArrayBufferView {
750 fn class_name() -> &'static str {
751 "ArrayBufferView"
752 }
753 fn is_exact(value: &v8::Local<v8::Value>) -> bool {
754 value.is_array_buffer_view()
755 }
756}