Skip to main content

wasm_bindgen/convert/
impls.rs

1use alloc::boxed::Box;
2use alloc::vec::Vec;
3use core::char;
4use core::mem::{self, ManuallyDrop};
5use core::ptr::NonNull;
6
7use crate::__rt::marker::ErasableGeneric;
8use crate::__rt::{WasmSignedWordRepr, WasmWordRepr};
9use crate::convert::traits::{WasmAbi, WasmPrimitive};
10use crate::convert::{
11    FromWasmAbi, IntoWasmAbi, LongRefFromWasmAbi, OptionFromWasmAbi, OptionIntoWasmAbi,
12    RefFromWasmAbi, ReturnWasmAbi, TryFromJsValue, UpcastFrom,
13};
14use crate::sys::Promising;
15use crate::sys::{JsOption, Undefined};
16use crate::{Clamped, JsError, JsValue, UnwrapThrowExt};
17
18// Primitive types can always be passed over the ABI.
19impl<T: WasmPrimitive> WasmAbi for T {
20    type Prim1 = Self;
21    type Prim2 = ();
22    type Prim3 = ();
23    type Prim4 = ();
24
25    #[inline]
26    fn split(self) -> (Self, (), (), ()) {
27        (self, (), (), ())
28    }
29
30    #[inline]
31    fn join(prim: Self, _: (), _: (), _: ()) -> Self {
32        prim
33    }
34}
35
36impl WasmAbi for i128 {
37    type Prim1 = u64;
38    type Prim2 = u64;
39    type Prim3 = ();
40    type Prim4 = ();
41
42    #[inline]
43    fn split(self) -> (u64, u64, (), ()) {
44        let low = self as u64;
45        let high = (self >> 64) as u64;
46        (low, high, (), ())
47    }
48
49    #[inline]
50    fn join(low: u64, high: u64, _: (), _: ()) -> Self {
51        (((high as u128) << 64) | low as u128) as i128
52    }
53}
54impl WasmAbi for u128 {
55    type Prim1 = u64;
56    type Prim2 = u64;
57    type Prim3 = ();
58    type Prim4 = ();
59
60    #[inline]
61    fn split(self) -> (u64, u64, (), ()) {
62        let low = self as u64;
63        let high = (self >> 64) as u64;
64        (low, high, (), ())
65    }
66
67    #[inline]
68    fn join(low: u64, high: u64, _: (), _: ()) -> Self {
69        ((high as u128) << 64) | low as u128
70    }
71}
72
73impl<T: WasmAbi<Prim4 = ()>> WasmAbi for Option<T> {
74    /// Whether this `Option` is a `Some` value.
75    type Prim1 = u32;
76    type Prim2 = T::Prim1;
77    type Prim3 = T::Prim2;
78    type Prim4 = T::Prim3;
79
80    #[inline]
81    fn split(self) -> (u32, T::Prim1, T::Prim2, T::Prim3) {
82        match self {
83            None => (
84                0,
85                Default::default(),
86                Default::default(),
87                Default::default(),
88            ),
89            Some(value) => {
90                let (prim1, prim2, prim3, ()) = value.split();
91                (1, prim1, prim2, prim3)
92            }
93        }
94    }
95
96    #[inline]
97    fn join(is_some: u32, prim1: T::Prim1, prim2: T::Prim2, prim3: T::Prim3) -> Self {
98        if is_some == 0 {
99            None
100        } else {
101            Some(T::join(prim1, prim2, prim3, ()))
102        }
103    }
104}
105
106macro_rules! type_wasm_native {
107    ($($t:tt as $c:tt)*) => ($(
108        impl IntoWasmAbi for $t {
109            type Abi = $c;
110
111            #[inline]
112            fn into_abi(self) -> $c { self as $c }
113        }
114
115        impl FromWasmAbi for $t {
116            type Abi = $c;
117
118            #[inline]
119            unsafe fn from_abi(js: $c) -> Self { js as $t }
120        }
121
122        impl IntoWasmAbi for Option<$t> {
123            type Abi = Option<$c>;
124
125            #[inline]
126            fn into_abi(self) -> Self::Abi {
127                self.map(|v| v as $c)
128            }
129        }
130
131        impl FromWasmAbi for Option<$t> {
132            type Abi = Option<$c>;
133
134            #[inline]
135            unsafe fn from_abi(js: Self::Abi) -> Self {
136                js.map(|v: $c| v as $t)
137            }
138        }
139
140        impl UpcastFrom<$t> for JsValue {}
141        impl UpcastFrom<$t> for JsOption<JsValue> {}
142        impl UpcastFrom<$t> for $t {}
143    )*)
144}
145
146type_wasm_native!(
147    i64 as i64
148    u64 as u64
149    i128 as i128
150    u128 as u128
151    f64 as f64
152);
153
154impl UpcastFrom<u64> for u128 {}
155impl UpcastFrom<u64> for JsOption<u128> {}
156impl UpcastFrom<i64> for i128 {}
157impl UpcastFrom<i64> for JsOption<i128> {}
158
159/// Sentinel value used to encode `None` for optional pointer-sized and
160/// 32-bit numeric values transferred over the JS `number` ABI.
161///
162/// `2^53 - 1` (`Number.MAX_SAFE_INTEGER`) is chosen because it is:
163/// - exactly representable as an `f64` (so JS round-trips it losslessly),
164/// - outside the range of any valid `i32`/`u32`/`f32` value (so it can't
165///   collide with a real `Some(...)` payload from those types), and
166/// - far above any plausible wasm64 pointer (which is bounded by the
167///   memory-64 address space limit, well below `2^53`).
168const F64_ABI_OPTION_SENTINEL: f64 = 9007199254740991_f64;
169
170macro_rules! type_wasm_native_f64_option {
171    ($($t:tt as $c:tt)*) => ($(
172        impl IntoWasmAbi for $t {
173            type Abi = $c;
174
175            #[inline]
176            fn into_abi(self) -> $c { self as $c }
177        }
178
179        impl FromWasmAbi for $t {
180            type Abi = $c;
181
182            #[inline]
183            unsafe fn from_abi(js: $c) -> Self { js as $t }
184        }
185
186        unsafe impl ErasableGeneric for $t {
187            type Repr = $t;
188        }
189
190        impl Promising for $t {
191            type Resolution = $t;
192        }
193
194        impl IntoWasmAbi for Option<$t> {
195            type Abi = f64;
196
197            #[inline]
198            fn into_abi(self) -> Self::Abi {
199                self.map(|v| v as $c as f64).unwrap_or(F64_ABI_OPTION_SENTINEL)
200            }
201        }
202
203        impl FromWasmAbi for Option<$t> {
204            type Abi = f64;
205
206            #[inline]
207            unsafe fn from_abi(js: Self::Abi) -> Self {
208                if js == F64_ABI_OPTION_SENTINEL {
209                    None
210                } else {
211                    Some(js as $c as $t)
212                }
213            }
214        }
215
216        impl UpcastFrom<$t> for JsValue {}
217        impl UpcastFrom<$t> for JsOption<JsValue> {}
218        impl UpcastFrom<$t> for $t {}
219    )*)
220}
221
222type_wasm_native_f64_option!(
223    i32 as i32
224    u32 as u32
225    f32 as f32
226    isize as WasmSignedWordRepr
227    usize as WasmWordRepr
228);
229
230#[cfg(target_pointer_width = "32")]
231impl UpcastFrom<isize> for i32 {}
232#[cfg(target_pointer_width = "32")]
233impl UpcastFrom<isize> for JsOption<i32> {}
234
235impl UpcastFrom<isize> for i64 {}
236impl UpcastFrom<isize> for JsOption<i64> {}
237impl UpcastFrom<isize> for i128 {}
238impl UpcastFrom<isize> for JsOption<i128> {}
239
240impl UpcastFrom<i32> for isize {}
241impl UpcastFrom<i32> for JsOption<isize> {}
242impl UpcastFrom<i32> for i64 {}
243impl UpcastFrom<i32> for JsOption<i64> {}
244impl UpcastFrom<i32> for i128 {}
245impl UpcastFrom<i32> for JsOption<i128> {}
246
247impl UpcastFrom<u32> for usize {}
248impl UpcastFrom<u32> for JsOption<usize> {}
249impl UpcastFrom<u32> for u64 {}
250impl UpcastFrom<u32> for JsOption<u64> {}
251impl UpcastFrom<u32> for u128 {}
252impl UpcastFrom<u32> for JsOption<u128> {}
253
254#[cfg(target_pointer_width = "32")]
255impl UpcastFrom<usize> for u32 {}
256#[cfg(target_pointer_width = "32")]
257impl UpcastFrom<usize> for JsOption<u32> {}
258impl UpcastFrom<usize> for u64 {}
259impl UpcastFrom<usize> for JsOption<u64> {}
260impl UpcastFrom<usize> for u128 {}
261impl UpcastFrom<usize> for JsOption<u128> {}
262
263impl UpcastFrom<f32> for f64 {}
264impl UpcastFrom<f32> for JsOption<f64> {}
265
266/// The sentinel value is 0xFF_FFFF for primitives with less than 32 bits.
267///
268/// This value is used, so all small primitive types (`bool`, `i8`, `u8`,
269/// `i16`, `u16`, `char`) can use the same JS glue code. `char::MAX` is
270/// 0x10_FFFF btw.
271const U32_ABI_OPTION_SENTINEL: u32 = 0x00FF_FFFFu32;
272
273macro_rules! type_abi_as_u32 {
274    ($($t:tt)*) => ($(
275        impl IntoWasmAbi for $t {
276            type Abi = u32;
277
278            #[inline]
279            fn into_abi(self) -> u32 { self as u32 }
280        }
281
282        impl FromWasmAbi for $t {
283            type Abi = u32;
284
285            #[inline]
286            unsafe fn from_abi(js: u32) -> Self { js as $t }
287        }
288
289        impl OptionIntoWasmAbi for $t {
290            #[inline]
291            fn none() -> u32 { U32_ABI_OPTION_SENTINEL }
292        }
293
294        impl OptionFromWasmAbi for $t {
295            #[inline]
296            fn is_none(js: &u32) -> bool { *js == U32_ABI_OPTION_SENTINEL }
297        }
298
299        unsafe impl ErasableGeneric for $t {
300            type Repr = $t;
301        }
302
303        impl Promising for $t {
304            type Resolution = $t;
305        }
306
307        impl UpcastFrom<$t> for JsValue {}
308        impl UpcastFrom<$t> for JsOption<JsValue> {}
309        impl UpcastFrom<$t> for $t {}
310    )*)
311}
312
313type_abi_as_u32!(i8 u8 i16 u16);
314
315impl UpcastFrom<i8> for i16 {}
316impl UpcastFrom<i8> for JsOption<i16> {}
317impl UpcastFrom<i8> for i32 {}
318impl UpcastFrom<i8> for JsOption<i32> {}
319impl UpcastFrom<i8> for i64 {}
320impl UpcastFrom<i8> for JsOption<i64> {}
321impl UpcastFrom<i8> for i128 {}
322impl UpcastFrom<i8> for JsOption<i128> {}
323
324impl UpcastFrom<u8> for u16 {}
325impl UpcastFrom<u8> for JsOption<u16> {}
326impl UpcastFrom<u8> for u32 {}
327impl UpcastFrom<u8> for JsOption<u32> {}
328impl UpcastFrom<u8> for u64 {}
329impl UpcastFrom<u8> for JsOption<u64> {}
330impl UpcastFrom<u8> for u128 {}
331impl UpcastFrom<u8> for JsOption<u128> {}
332
333impl UpcastFrom<i16> for i32 {}
334impl UpcastFrom<i16> for JsOption<i32> {}
335impl UpcastFrom<i16> for i64 {}
336impl UpcastFrom<i16> for JsOption<i64> {}
337impl UpcastFrom<i16> for i128 {}
338impl UpcastFrom<i16> for JsOption<i128> {}
339
340impl UpcastFrom<u16> for u32 {}
341impl UpcastFrom<u16> for JsOption<u32> {}
342impl UpcastFrom<u16> for u64 {}
343impl UpcastFrom<u16> for JsOption<u64> {}
344impl UpcastFrom<u16> for u128 {}
345impl UpcastFrom<u16> for JsOption<u128> {}
346
347impl IntoWasmAbi for bool {
348    type Abi = u32;
349
350    #[inline]
351    fn into_abi(self) -> u32 {
352        self as u32
353    }
354}
355
356impl FromWasmAbi for bool {
357    type Abi = u32;
358
359    #[inline]
360    unsafe fn from_abi(js: u32) -> bool {
361        js != 0
362    }
363}
364
365impl OptionIntoWasmAbi for bool {
366    #[inline]
367    fn none() -> u32 {
368        U32_ABI_OPTION_SENTINEL
369    }
370}
371
372impl OptionFromWasmAbi for bool {
373    #[inline]
374    fn is_none(js: &u32) -> bool {
375        *js == U32_ABI_OPTION_SENTINEL
376    }
377}
378
379unsafe impl ErasableGeneric for bool {
380    type Repr = bool;
381}
382
383impl Promising for bool {
384    type Resolution = bool;
385}
386
387impl UpcastFrom<bool> for JsValue {}
388impl UpcastFrom<bool> for JsOption<JsValue> {}
389impl UpcastFrom<bool> for bool {}
390
391impl IntoWasmAbi for char {
392    type Abi = u32;
393
394    #[inline]
395    fn into_abi(self) -> u32 {
396        self as u32
397    }
398}
399
400impl FromWasmAbi for char {
401    type Abi = u32;
402
403    #[inline]
404    unsafe fn from_abi(js: u32) -> char {
405        // SAFETY: Checked in bindings.
406        char::from_u32_unchecked(js)
407    }
408}
409
410impl OptionIntoWasmAbi for char {
411    #[inline]
412    fn none() -> u32 {
413        U32_ABI_OPTION_SENTINEL
414    }
415}
416
417impl OptionFromWasmAbi for char {
418    #[inline]
419    fn is_none(js: &u32) -> bool {
420        *js == U32_ABI_OPTION_SENTINEL
421    }
422}
423
424unsafe impl ErasableGeneric for char {
425    type Repr = char;
426}
427
428impl Promising for char {
429    type Resolution = char;
430}
431
432impl UpcastFrom<char> for JsValue {}
433impl UpcastFrom<char> for JsOption<JsValue> {}
434impl UpcastFrom<char> for char {}
435
436impl<T> IntoWasmAbi for *const T {
437    type Abi = WasmWordRepr;
438
439    #[inline]
440    fn into_abi(self) -> Self::Abi {
441        self as usize as WasmWordRepr
442    }
443}
444
445impl<T> FromWasmAbi for *const T {
446    type Abi = WasmWordRepr;
447
448    #[inline]
449    unsafe fn from_abi(js: Self::Abi) -> *const T {
450        js as usize as *const T
451    }
452}
453
454unsafe impl<T: ErasableGeneric> ErasableGeneric for *const T {
455    type Repr = *const T::Repr;
456}
457
458impl<T, Target> UpcastFrom<*const T> for *const Target where Target: UpcastFrom<T> {}
459impl<T, Target> UpcastFrom<*const T> for JsOption<*const Target> where Target: UpcastFrom<T> {}
460
461impl<T> IntoWasmAbi for Option<*const T> {
462    type Abi = f64;
463
464    #[inline]
465    fn into_abi(self) -> Self::Abi {
466        self.map(|ptr| ptr as usize as f64)
467            .unwrap_or(F64_ABI_OPTION_SENTINEL)
468    }
469}
470
471unsafe impl<T: ErasableGeneric> ErasableGeneric for Option<T> {
472    type Repr = Option<<T as ErasableGeneric>::Repr>;
473}
474
475impl<T, Target> UpcastFrom<Option<T>> for Option<Target> where Target: UpcastFrom<T> {}
476impl<T, Target> UpcastFrom<Option<T>> for JsOption<Option<Target>> where Target: UpcastFrom<T> {}
477
478impl<T> FromWasmAbi for Option<*const T> {
479    type Abi = f64;
480
481    #[inline]
482    unsafe fn from_abi(js: Self::Abi) -> Option<*const T> {
483        if js == F64_ABI_OPTION_SENTINEL {
484            None
485        } else {
486            Some(js as usize as *const T)
487        }
488    }
489}
490
491impl<T> IntoWasmAbi for *mut T {
492    type Abi = WasmWordRepr;
493
494    #[inline]
495    fn into_abi(self) -> Self::Abi {
496        self as usize as WasmWordRepr
497    }
498}
499
500impl<T> FromWasmAbi for *mut T {
501    type Abi = WasmWordRepr;
502
503    #[inline]
504    unsafe fn from_abi(js: Self::Abi) -> *mut T {
505        js as usize as *mut T
506    }
507}
508
509impl<T> IntoWasmAbi for Option<*mut T> {
510    type Abi = f64;
511
512    #[inline]
513    fn into_abi(self) -> Self::Abi {
514        self.map(|ptr| ptr as usize as f64)
515            .unwrap_or(F64_ABI_OPTION_SENTINEL)
516    }
517}
518
519impl<T> FromWasmAbi for Option<*mut T> {
520    type Abi = f64;
521
522    #[inline]
523    unsafe fn from_abi(js: Self::Abi) -> Option<*mut T> {
524        if js == F64_ABI_OPTION_SENTINEL {
525            None
526        } else {
527            Some(js as usize as *mut T)
528        }
529    }
530}
531
532impl<T> IntoWasmAbi for NonNull<T> {
533    type Abi = WasmWordRepr;
534
535    #[inline]
536    fn into_abi(self) -> Self::Abi {
537        self.as_ptr() as usize as WasmWordRepr
538    }
539}
540
541impl<T> OptionIntoWasmAbi for NonNull<T> {
542    #[inline]
543    fn none() -> Self::Abi {
544        0 as WasmWordRepr
545    }
546}
547
548impl<T> FromWasmAbi for NonNull<T> {
549    type Abi = WasmWordRepr;
550
551    #[inline]
552    unsafe fn from_abi(js: Self::Abi) -> Self {
553        // SAFETY: Checked in bindings.
554        NonNull::new_unchecked(js as usize as *mut T)
555    }
556}
557
558impl<T> OptionFromWasmAbi for NonNull<T> {
559    #[inline]
560    fn is_none(js: &Self::Abi) -> bool {
561        *js == 0 as WasmWordRepr
562    }
563}
564
565impl IntoWasmAbi for JsValue {
566    type Abi = u32;
567
568    #[inline]
569    fn into_abi(self) -> u32 {
570        let ret = self.idx;
571        mem::forget(self);
572        ret
573    }
574}
575
576impl FromWasmAbi for JsValue {
577    type Abi = u32;
578
579    #[inline]
580    unsafe fn from_abi(js: u32) -> JsValue {
581        JsValue::_new(js)
582    }
583}
584
585impl IntoWasmAbi for &JsValue {
586    type Abi = u32;
587
588    #[inline]
589    fn into_abi(self) -> u32 {
590        self.idx
591    }
592}
593
594impl RefFromWasmAbi for JsValue {
595    type Abi = u32;
596    type Anchor = ManuallyDrop<JsValue>;
597
598    #[inline]
599    unsafe fn ref_from_abi(js: u32) -> Self::Anchor {
600        ManuallyDrop::new(JsValue::_new(js))
601    }
602}
603
604impl LongRefFromWasmAbi for JsValue {
605    type Abi = u32;
606    type Anchor = JsValue;
607
608    #[inline]
609    unsafe fn long_ref_from_abi(js: u32) -> Self::Anchor {
610        Self::from_abi(js)
611    }
612}
613
614impl OptionIntoWasmAbi for JsValue {
615    #[inline]
616    fn none() -> u32 {
617        crate::__rt::JSIDX_UNDEFINED
618    }
619}
620
621impl OptionIntoWasmAbi for &JsValue {
622    #[inline]
623    fn none() -> u32 {
624        crate::__rt::JSIDX_UNDEFINED
625    }
626}
627
628impl OptionFromWasmAbi for JsValue {
629    #[inline]
630    fn is_none(js: &u32) -> bool {
631        unsafe { Self::ref_from_abi(*js) }.is_undefined()
632    }
633}
634
635impl<T: OptionIntoWasmAbi> IntoWasmAbi for Option<T> {
636    type Abi = T::Abi;
637
638    #[inline]
639    fn into_abi(self) -> T::Abi {
640        match self {
641            None => T::none(),
642            Some(me) => me.into_abi(),
643        }
644    }
645}
646
647impl<T: OptionFromWasmAbi> FromWasmAbi for Option<T> {
648    type Abi = T::Abi;
649
650    #[inline]
651    unsafe fn from_abi(js: T::Abi) -> Self {
652        if T::is_none(&js) {
653            None
654        } else {
655            Some(T::from_abi(js))
656        }
657    }
658}
659
660impl<T: OptionIntoWasmAbi + ErasableGeneric<Repr = JsValue> + Promising> Promising for Option<T> {
661    type Resolution = Option<<T as Promising>::Resolution>;
662}
663
664impl<T: IntoWasmAbi> IntoWasmAbi for Clamped<T> {
665    type Abi = T::Abi;
666
667    #[inline]
668    fn into_abi(self) -> Self::Abi {
669        self.0.into_abi()
670    }
671}
672
673impl<T: FromWasmAbi> FromWasmAbi for Clamped<T> {
674    type Abi = T::Abi;
675
676    #[inline]
677    unsafe fn from_abi(js: T::Abi) -> Self {
678        Clamped(T::from_abi(js))
679    }
680}
681
682impl IntoWasmAbi for () {
683    type Abi = ();
684
685    #[inline]
686    fn into_abi(self) {
687        self
688    }
689}
690
691impl FromWasmAbi for () {
692    type Abi = ();
693
694    #[inline]
695    unsafe fn from_abi(_js: ()) {}
696}
697
698impl Promising for () {
699    type Resolution = Undefined;
700}
701
702impl UpcastFrom<()> for JsValue {}
703impl UpcastFrom<()> for () {}
704
705unsafe impl ErasableGeneric for () {
706    type Repr = ();
707}
708
709impl<T: WasmAbi<Prim3 = (), Prim4 = ()>> WasmAbi for Result<T, u32> {
710    type Prim1 = T::Prim1;
711    type Prim2 = T::Prim2;
712    // The order of primitives here is such that we can pop() the possible error
713    // first, deal with it and move on. Later primitives are popped off the
714    // stack first.
715    /// If this `Result` is an `Err`, the error value.
716    type Prim3 = u32;
717    /// Whether this `Result` is an `Err`.
718    type Prim4 = u32;
719
720    #[inline]
721    fn split(self) -> (T::Prim1, T::Prim2, u32, u32) {
722        match self {
723            Ok(value) => {
724                let (prim1, prim2, (), ()) = value.split();
725                (prim1, prim2, 0, 0)
726            }
727            Err(err) => (Default::default(), Default::default(), err, 1),
728        }
729    }
730
731    #[inline]
732    fn join(prim1: T::Prim1, prim2: T::Prim2, err: u32, is_err: u32) -> Self {
733        if is_err == 0 {
734            Ok(T::join(prim1, prim2, (), ()))
735        } else {
736            Err(err)
737        }
738    }
739}
740
741impl<T, E> ReturnWasmAbi for Result<T, E>
742where
743    T: IntoWasmAbi,
744    E: Into<JsValue>,
745    T::Abi: WasmAbi<Prim3 = (), Prim4 = ()>,
746{
747    type Abi = Result<T::Abi, u32>;
748
749    #[inline]
750    fn return_abi(self) -> Self::Abi {
751        match self {
752            Ok(v) => Ok(v.into_abi()),
753            Err(e) => {
754                let jsval = e.into();
755                Err(jsval.into_abi())
756            }
757        }
758    }
759}
760
761unsafe impl<T: ErasableGeneric, E: ErasableGeneric> ErasableGeneric for Result<T, E> {
762    type Repr = Result<<T as ErasableGeneric>::Repr, <E as ErasableGeneric>::Repr>;
763}
764
765impl<T: ErasableGeneric + Promising, E: ErasableGeneric> Promising for Result<T, E> {
766    type Resolution = Result<<T as Promising>::Resolution, E>;
767}
768
769impl<T, E, TargetT, TargetE> UpcastFrom<Result<T, E>> for Result<TargetT, TargetE>
770where
771    TargetT: UpcastFrom<T>,
772    TargetE: UpcastFrom<E>,
773{
774}
775impl<T, E, TargetT, TargetE> UpcastFrom<Result<T, E>> for JsOption<Result<TargetT, TargetE>>
776where
777    TargetT: UpcastFrom<T>,
778    TargetE: UpcastFrom<E>,
779{
780}
781
782unsafe impl ErasableGeneric for JsError {
783    type Repr = JsValue;
784}
785
786impl IntoWasmAbi for JsError {
787    type Abi = <JsValue as IntoWasmAbi>::Abi;
788
789    fn into_abi(self) -> Self::Abi {
790        self.value.into_abi()
791    }
792}
793
794// `JsError` is `#[repr(transparent)]` over `JsValue`
795impl FromWasmAbi for JsError {
796    type Abi = <JsValue as FromWasmAbi>::Abi;
797
798    #[inline]
799    unsafe fn from_abi(js: Self::Abi) -> Self {
800        JsError {
801            value: JsValue::from_abi(js),
802        }
803    }
804}
805
806impl Promising for JsError {
807    type Resolution = JsError;
808}
809
810impl UpcastFrom<JsError> for JsValue {}
811impl UpcastFrom<JsError> for JsOption<JsValue> {}
812impl UpcastFrom<JsError> for JsError {}
813
814/// # ⚠️ Unstable
815///
816/// This is part of the internal [`convert`](crate::convert) module, **no
817/// stability guarantees** are provided. Use at your own risk. See its
818/// documentation for more details.
819// Note: this can't take `&[T]` because the `Into<JsValue>` impl needs
820// ownership of `T`.
821pub fn js_value_vector_into_abi<T: Into<JsValue>>(
822    vector: Box<[T]>,
823) -> <Box<[JsValue]> as IntoWasmAbi>::Abi {
824    let js_vals: Box<[JsValue]> = vector.into_vec().into_iter().map(|x| x.into()).collect();
825
826    js_vals.into_abi()
827}
828
829/// # ⚠️ Unstable
830///
831/// This is part of the internal [`convert`](crate::convert) module, **no
832/// stability guarantees** are provided. Use at your own risk. See its
833/// documentation for more details.
834pub unsafe fn js_value_vector_from_abi<T: TryFromJsValue>(
835    js: <Box<[JsValue]> as FromWasmAbi>::Abi,
836) -> Box<[T]> {
837    let js_vals = <Vec<JsValue> as FromWasmAbi>::from_abi(js);
838
839    let mut result = Vec::with_capacity(js_vals.len());
840    for value in js_vals {
841        // We push elements one-by-one instead of using `collect` in order to improve
842        // error messages. When using `collect`, this `expect_throw` is buried in a
843        // giant chain of internal iterator functions, which results in the actual
844        // function that takes this `Vec` falling off the end of the call stack.
845        // So instead, make sure to call it directly within this function.
846        //
847        // This is only a problem in debug mode. Since this is the browser's error stack
848        // we're talking about, it can only see functions that actually make it to the
849        // final Wasm binary (i.e., not inlined functions). All of those internal
850        // iterator functions get inlined in release mode, and so they don't show up.
851        result.push(
852            T::try_from_js_value(value).expect_throw("array contains a value of the wrong type"),
853        );
854    }
855    result.into_boxed_slice()
856}