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