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