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, MaybeFromWasmAbi, MaybeIntoWasmAbi,
12    NullableFromWasmAbi, NullableIntoWasmAbi, OptionFromWasmAbi, OptionIntoWasmAbi, RefFromWasmAbi,
13    ReturnWasmAbi, TryFromJsValue, UpcastFrom,
14};
15use crate::sys::Promising;
16use crate::sys::{JsNullable, JsOption, Undefined};
17use crate::{throw_str, Clamped, JsError, JsValue, Nullable};
18
19// Primitive types can always be passed over the ABI.
20impl<T: WasmPrimitive> WasmAbi for T {
21    type Prim1 = Self;
22    type Prim2 = ();
23    type Prim3 = ();
24    type Prim4 = ();
25
26    #[inline]
27    fn split(self) -> (Self, (), (), ()) {
28        (self, (), (), ())
29    }
30
31    #[inline]
32    fn join(prim: Self, _: (), _: (), _: ()) -> Self {
33        prim
34    }
35}
36
37impl WasmAbi for i128 {
38    type Prim1 = u64;
39    type Prim2 = u64;
40    type Prim3 = ();
41    type Prim4 = ();
42
43    #[inline]
44    fn split(self) -> (u64, u64, (), ()) {
45        let low = self as u64;
46        let high = (self >> 64) as u64;
47        (low, high, (), ())
48    }
49
50    #[inline]
51    fn join(low: u64, high: u64, _: (), _: ()) -> Self {
52        (((high as u128) << 64) | low as u128) as i128
53    }
54}
55impl WasmAbi for u128 {
56    type Prim1 = u64;
57    type Prim2 = u64;
58    type Prim3 = ();
59    type Prim4 = ();
60
61    #[inline]
62    fn split(self) -> (u64, u64, (), ()) {
63        let low = self as u64;
64        let high = (self >> 64) as u64;
65        (low, high, (), ())
66    }
67
68    #[inline]
69    fn join(low: u64, high: u64, _: (), _: ()) -> Self {
70        ((high as u128) << 64) | low as u128
71    }
72}
73
74/// The ABI of `Option<T>`, `Nullable<T>` and `Option<Nullable<T>>` for a `T`
75/// whose own ABI has no spare value: `tag` is `0` for `None`, `1` for a value
76/// and `2` for `Null`.
77#[doc(hidden)]
78#[derive(Clone, Copy)]
79pub struct MaybeAbi<T> {
80    pub tag: u32,
81    pub value: T,
82}
83
84impl<T: WasmAbi<Prim4 = ()>> WasmAbi for MaybeAbi<T> {
85    type Prim1 = u32;
86    type Prim2 = T::Prim1;
87    type Prim3 = T::Prim2;
88    type Prim4 = T::Prim3;
89
90    #[inline]
91    fn split(self) -> (u32, T::Prim1, T::Prim2, T::Prim3) {
92        let (prim1, prim2, prim3, ()) = self.value.split();
93        (self.tag, prim1, prim2, prim3)
94    }
95
96    #[inline]
97    fn join(tag: u32, prim1: T::Prim1, prim2: T::Prim2, prim3: T::Prim3) -> Self {
98        MaybeAbi {
99            tag,
100            value: 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 MaybeIntoWasmAbi for $t {
122            type MaybeAbi = MaybeAbi<$c>;
123
124            #[inline]
125            fn into_maybe_abi(self) -> MaybeAbi<$c> {
126                MaybeAbi { tag: 1, value: self as $c }
127            }
128
129            #[inline]
130            fn none() -> MaybeAbi<$c> {
131                MaybeAbi { tag: 0, value: 0 as $c }
132            }
133        }
134
135        impl NullableIntoWasmAbi for $t {
136            #[inline]
137            fn null() -> MaybeAbi<$c> {
138                MaybeAbi { tag: 2, value: 0 as $c }
139            }
140        }
141
142        impl MaybeFromWasmAbi for $t {
143            type MaybeAbi = MaybeAbi<$c>;
144
145            #[inline]
146            unsafe fn from_maybe_abi(js: MaybeAbi<$c>) -> Self {
147                js.value as $t
148            }
149
150            #[inline]
151            fn is_none(js: &MaybeAbi<$c>) -> bool {
152                js.tag == 0
153            }
154        }
155
156        impl NullableFromWasmAbi for $t {
157            #[inline]
158            fn is_null(js: &MaybeAbi<$c>) -> bool {
159                js.tag == 2
160            }
161        }
162
163        impl UpcastFrom<$t> for JsValue {}
164        impl UpcastFrom<$t> for JsOption<JsValue> {}
165        impl UpcastFrom<$t> for JsNullable<JsValue> {}
166        impl UpcastFrom<$t> for $t {}
167        impl<Target: UpcastFrom<$t>> UpcastFrom<$t> for Option<Target> {}
168        impl<Target: UpcastFrom<$t>> UpcastFrom<$t> for Nullable<Target> {}
169    )*)
170}
171
172type_wasm_native!(
173    i64 as i64
174    u64 as u64
175    i128 as i128
176    u128 as u128
177    f64 as f64
178);
179
180impl UpcastFrom<u64> for u128 {}
181impl UpcastFrom<u64> for JsOption<u128> {}
182impl UpcastFrom<u64> for JsNullable<u128> {}
183impl UpcastFrom<i64> for i128 {}
184impl UpcastFrom<i64> for JsOption<i128> {}
185impl UpcastFrom<i64> for JsNullable<i128> {}
186
187/// Sentinel value used to encode `None` for optional pointer-sized and
188/// 32-bit numeric values transferred over the JS `number` ABI.
189///
190/// `2^53 - 1` (`Number.MAX_SAFE_INTEGER`) is chosen because it is:
191/// - exactly representable as an `f64` (so JS round-trips it losslessly),
192/// - outside the range of any valid `i32`/`u32`/`f32` value (so it can't
193///   collide with a real `Some(...)` payload from those types), and
194/// - far above any plausible wasm64 pointer (which is bounded by the
195///   memory-64 address space limit, well below `2^53`).
196const F64_ABI_OPTION_SENTINEL: f64 = 9007199254740991_f64;
197
198/// `Nullable::Null` over the JS `number` ABI: the safe integer below
199/// [`F64_ABI_OPTION_SENTINEL`], outside every value range for the same
200/// reasons.
201#[doc(hidden)]
202pub const F64_ABI_NULL_SENTINEL: f64 = 9007199254740990_f64;
203
204macro_rules! type_wasm_native_f64_option {
205    ($($t:tt as $c:tt)*) => ($(
206        impl IntoWasmAbi for $t {
207            type Abi = $c;
208
209            #[inline]
210            fn into_abi(self) -> $c { self as $c }
211        }
212
213        impl FromWasmAbi for $t {
214            type Abi = $c;
215
216            #[inline]
217            unsafe fn from_abi(js: $c) -> Self { js as $t }
218        }
219
220        unsafe impl ErasableGeneric for $t {
221            type Repr = $t;
222        }
223
224        impl Promising for $t {
225            type Resolution = $t;
226        }
227
228        impl MaybeIntoWasmAbi for $t {
229            type MaybeAbi = f64;
230
231            #[inline]
232            fn into_maybe_abi(self) -> f64 {
233                self as $c as f64
234            }
235
236            #[inline]
237            fn none() -> f64 {
238                F64_ABI_OPTION_SENTINEL
239            }
240        }
241
242        impl NullableIntoWasmAbi for $t {
243            #[inline]
244            fn null() -> f64 {
245                F64_ABI_NULL_SENTINEL
246            }
247        }
248
249        impl MaybeFromWasmAbi for $t {
250            type MaybeAbi = f64;
251
252            #[inline]
253            unsafe fn from_maybe_abi(js: f64) -> Self {
254                js as $c as $t
255            }
256
257            #[inline]
258            fn is_none(js: &f64) -> bool {
259                *js == F64_ABI_OPTION_SENTINEL
260            }
261        }
262
263        impl NullableFromWasmAbi for $t {
264            #[inline]
265            fn is_null(js: &f64) -> bool {
266                *js == F64_ABI_NULL_SENTINEL
267            }
268        }
269
270        impl UpcastFrom<$t> for JsValue {}
271        impl UpcastFrom<$t> for JsOption<JsValue> {}
272        impl UpcastFrom<$t> for JsNullable<JsValue> {}
273        impl UpcastFrom<$t> for $t {}
274        impl<Target: UpcastFrom<$t>> UpcastFrom<$t> for Option<Target> {}
275        impl<Target: UpcastFrom<$t>> UpcastFrom<$t> for Nullable<Target> {}
276    )*)
277}
278
279type_wasm_native_f64_option!(
280    i32 as i32
281    u32 as u32
282    f32 as f32
283    isize as WasmSignedWordRepr
284    usize as WasmWordRepr
285);
286
287#[cfg(target_pointer_width = "32")]
288impl UpcastFrom<isize> for i32 {}
289#[cfg(target_pointer_width = "32")]
290impl UpcastFrom<isize> for JsOption<i32> {}
291#[cfg(target_pointer_width = "32")]
292impl UpcastFrom<isize> for JsNullable<i32> {}
293
294impl UpcastFrom<isize> for i64 {}
295impl UpcastFrom<isize> for JsOption<i64> {}
296impl UpcastFrom<isize> for JsNullable<i64> {}
297impl UpcastFrom<isize> for i128 {}
298impl UpcastFrom<isize> for JsOption<i128> {}
299impl UpcastFrom<isize> for JsNullable<i128> {}
300
301impl UpcastFrom<i32> for isize {}
302impl UpcastFrom<i32> for JsOption<isize> {}
303impl UpcastFrom<i32> for JsNullable<isize> {}
304impl UpcastFrom<i32> for i64 {}
305impl UpcastFrom<i32> for JsOption<i64> {}
306impl UpcastFrom<i32> for JsNullable<i64> {}
307impl UpcastFrom<i32> for i128 {}
308impl UpcastFrom<i32> for JsOption<i128> {}
309impl UpcastFrom<i32> for JsNullable<i128> {}
310
311impl UpcastFrom<u32> for usize {}
312impl UpcastFrom<u32> for JsOption<usize> {}
313impl UpcastFrom<u32> for JsNullable<usize> {}
314impl UpcastFrom<u32> for u64 {}
315impl UpcastFrom<u32> for JsOption<u64> {}
316impl UpcastFrom<u32> for JsNullable<u64> {}
317impl UpcastFrom<u32> for u128 {}
318impl UpcastFrom<u32> for JsOption<u128> {}
319impl UpcastFrom<u32> for JsNullable<u128> {}
320
321#[cfg(target_pointer_width = "32")]
322impl UpcastFrom<usize> for u32 {}
323#[cfg(target_pointer_width = "32")]
324impl UpcastFrom<usize> for JsOption<u32> {}
325#[cfg(target_pointer_width = "32")]
326impl UpcastFrom<usize> for JsNullable<u32> {}
327impl UpcastFrom<usize> for u64 {}
328impl UpcastFrom<usize> for JsOption<u64> {}
329impl UpcastFrom<usize> for JsNullable<u64> {}
330impl UpcastFrom<usize> for u128 {}
331impl UpcastFrom<usize> for JsOption<u128> {}
332impl UpcastFrom<usize> for JsNullable<u128> {}
333
334impl UpcastFrom<f32> for f64 {}
335impl UpcastFrom<f32> for JsOption<f64> {}
336impl UpcastFrom<f32> for JsNullable<f64> {}
337
338/// The sentinel value is 0xFF_FFFF for primitives with less than 32 bits.
339///
340/// This value is used, so all small primitive types (`bool`, `i8`, `u8`,
341/// `i16`, `u16`, `char`) can use the same JS glue code. `char::MAX` is
342/// 0x10_FFFF btw.
343const U32_ABI_OPTION_SENTINEL: u32 = 0x00FF_FFFFu32;
344
345/// `Nullable::Null` for the same types, below the `Option` sentinel.
346const U32_ABI_NULL_SENTINEL: u32 = 0x00FF_FFFEu32;
347
348macro_rules! type_abi_as_u32 {
349    ($($t:tt)*) => ($(
350        impl IntoWasmAbi for $t {
351            type Abi = u32;
352
353            #[inline]
354            fn into_abi(self) -> u32 { self as u32 }
355        }
356
357        impl FromWasmAbi for $t {
358            type Abi = u32;
359
360            #[inline]
361            unsafe fn from_abi(js: u32) -> Self { js as $t }
362        }
363
364        impl OptionIntoWasmAbi for $t {
365            #[inline]
366            fn none() -> u32 { U32_ABI_OPTION_SENTINEL }
367        }
368
369        impl OptionFromWasmAbi for $t {
370            #[inline]
371            fn is_none(js: &u32) -> bool { *js == U32_ABI_OPTION_SENTINEL }
372        }
373
374        impl_nullable_into_shared_abi!(null = U32_ABI_NULL_SENTINEL; [] $t);
375        impl_nullable_from_shared_abi!(is_null = |js| *js == U32_ABI_NULL_SENTINEL; [] $t);
376
377        unsafe impl ErasableGeneric for $t {
378            type Repr = $t;
379        }
380
381        impl Promising for $t {
382            type Resolution = $t;
383        }
384
385        impl UpcastFrom<$t> for JsValue {}
386        impl UpcastFrom<$t> for JsOption<JsValue> {}
387        impl UpcastFrom<$t> for JsNullable<JsValue> {}
388        impl UpcastFrom<$t> for $t {}
389        impl<Target: UpcastFrom<$t>> UpcastFrom<$t> for Option<Target> {}
390        impl<Target: UpcastFrom<$t>> UpcastFrom<$t> for Nullable<Target> {}
391    )*)
392}
393
394type_abi_as_u32!(i8 u8 i16 u16);
395
396impl UpcastFrom<i8> for i16 {}
397impl UpcastFrom<i8> for JsOption<i16> {}
398impl UpcastFrom<i8> for JsNullable<i16> {}
399impl UpcastFrom<i8> for i32 {}
400impl UpcastFrom<i8> for JsOption<i32> {}
401impl UpcastFrom<i8> for JsNullable<i32> {}
402impl UpcastFrom<i8> for i64 {}
403impl UpcastFrom<i8> for JsOption<i64> {}
404impl UpcastFrom<i8> for JsNullable<i64> {}
405impl UpcastFrom<i8> for i128 {}
406impl UpcastFrom<i8> for JsOption<i128> {}
407impl UpcastFrom<i8> for JsNullable<i128> {}
408
409impl UpcastFrom<u8> for u16 {}
410impl UpcastFrom<u8> for JsOption<u16> {}
411impl UpcastFrom<u8> for JsNullable<u16> {}
412impl UpcastFrom<u8> for u32 {}
413impl UpcastFrom<u8> for JsOption<u32> {}
414impl UpcastFrom<u8> for JsNullable<u32> {}
415impl UpcastFrom<u8> for u64 {}
416impl UpcastFrom<u8> for JsOption<u64> {}
417impl UpcastFrom<u8> for JsNullable<u64> {}
418impl UpcastFrom<u8> for u128 {}
419impl UpcastFrom<u8> for JsOption<u128> {}
420impl UpcastFrom<u8> for JsNullable<u128> {}
421
422impl UpcastFrom<i16> for i32 {}
423impl UpcastFrom<i16> for JsOption<i32> {}
424impl UpcastFrom<i16> for JsNullable<i32> {}
425impl UpcastFrom<i16> for i64 {}
426impl UpcastFrom<i16> for JsOption<i64> {}
427impl UpcastFrom<i16> for JsNullable<i64> {}
428impl UpcastFrom<i16> for i128 {}
429impl UpcastFrom<i16> for JsOption<i128> {}
430impl UpcastFrom<i16> for JsNullable<i128> {}
431
432impl UpcastFrom<u16> for u32 {}
433impl UpcastFrom<u16> for JsOption<u32> {}
434impl UpcastFrom<u16> for JsNullable<u32> {}
435impl UpcastFrom<u16> for u64 {}
436impl UpcastFrom<u16> for JsOption<u64> {}
437impl UpcastFrom<u16> for JsNullable<u64> {}
438impl UpcastFrom<u16> for u128 {}
439impl UpcastFrom<u16> for JsOption<u128> {}
440impl UpcastFrom<u16> for JsNullable<u128> {}
441
442impl IntoWasmAbi for bool {
443    type Abi = u32;
444
445    #[inline]
446    fn into_abi(self) -> u32 {
447        self as u32
448    }
449}
450
451impl FromWasmAbi for bool {
452    type Abi = u32;
453
454    #[inline]
455    unsafe fn from_abi(js: u32) -> bool {
456        js != 0
457    }
458}
459
460impl OptionIntoWasmAbi for bool {
461    #[inline]
462    fn none() -> u32 {
463        U32_ABI_OPTION_SENTINEL
464    }
465}
466
467impl OptionFromWasmAbi for bool {
468    #[inline]
469    fn is_none(js: &u32) -> bool {
470        *js == U32_ABI_OPTION_SENTINEL
471    }
472}
473
474impl_nullable_into_shared_abi!(null = U32_ABI_NULL_SENTINEL; [] bool);
475impl_nullable_from_shared_abi!(is_null = |js| *js == U32_ABI_NULL_SENTINEL; [] bool);
476
477unsafe impl ErasableGeneric for bool {
478    type Repr = bool;
479}
480
481impl Promising for bool {
482    type Resolution = bool;
483}
484
485impl UpcastFrom<bool> for JsValue {}
486impl UpcastFrom<bool> for JsOption<JsValue> {}
487impl UpcastFrom<bool> for JsNullable<JsValue> {}
488impl UpcastFrom<bool> for bool {}
489impl<Target: UpcastFrom<bool>> UpcastFrom<bool> for Option<Target> {}
490impl<Target: UpcastFrom<bool>> UpcastFrom<bool> for Nullable<Target> {}
491
492impl IntoWasmAbi for char {
493    type Abi = u32;
494
495    #[inline]
496    fn into_abi(self) -> u32 {
497        self as u32
498    }
499}
500
501impl FromWasmAbi for char {
502    type Abi = u32;
503
504    #[inline]
505    unsafe fn from_abi(js: u32) -> char {
506        // SAFETY: Checked in bindings.
507        char::from_u32_unchecked(js)
508    }
509}
510
511impl OptionIntoWasmAbi for char {
512    #[inline]
513    fn none() -> u32 {
514        U32_ABI_OPTION_SENTINEL
515    }
516}
517
518impl OptionFromWasmAbi for char {
519    #[inline]
520    fn is_none(js: &u32) -> bool {
521        *js == U32_ABI_OPTION_SENTINEL
522    }
523}
524
525impl_nullable_into_shared_abi!(null = U32_ABI_NULL_SENTINEL; [] char);
526impl_nullable_from_shared_abi!(is_null = |js| *js == U32_ABI_NULL_SENTINEL; [] char);
527
528unsafe impl ErasableGeneric for char {
529    type Repr = char;
530}
531
532impl Promising for char {
533    type Resolution = char;
534}
535
536impl UpcastFrom<char> for JsValue {}
537impl UpcastFrom<char> for JsOption<JsValue> {}
538impl UpcastFrom<char> for JsNullable<JsValue> {}
539impl UpcastFrom<char> for char {}
540impl<Target: UpcastFrom<char>> UpcastFrom<char> for Option<Target> {}
541impl<Target: UpcastFrom<char>> UpcastFrom<char> for Nullable<Target> {}
542
543impl<T> IntoWasmAbi for *const T {
544    type Abi = WasmWordRepr;
545
546    #[inline]
547    fn into_abi(self) -> Self::Abi {
548        self as usize as WasmWordRepr
549    }
550}
551
552impl<T> FromWasmAbi for *const T {
553    type Abi = WasmWordRepr;
554
555    #[inline]
556    unsafe fn from_abi(js: Self::Abi) -> *const T {
557        js as usize as *const T
558    }
559}
560
561unsafe impl<T: ErasableGeneric> ErasableGeneric for *const T {
562    type Repr = *const T::Repr;
563}
564
565impl<T, Target> UpcastFrom<*const T> for *const Target where Target: UpcastFrom<T> {}
566impl<T, Target> UpcastFrom<*const T> for JsOption<*const Target> where Target: UpcastFrom<T> {}
567impl<T, Target> UpcastFrom<*const T> for JsNullable<*const Target> where Target: UpcastFrom<T> {}
568
569unsafe impl<T: ErasableGeneric> ErasableGeneric for Option<T> {
570    type Repr = Option<<T as ErasableGeneric>::Repr>;
571}
572
573impl<T, Target> UpcastFrom<Option<T>> for Option<Target> where Target: UpcastFrom<T> {}
574impl<T, Target> UpcastFrom<Option<T>> for JsOption<Option<Target>> where Target: UpcastFrom<T> {}
575impl<T, Target> UpcastFrom<Option<T>> for JsNullable<Option<Target>> where Target: UpcastFrom<T> {}
576// `None` is `undefined`, a JS value, so an optional carrier upcasts to `JsValue`
577// whenever its payload does, as each scalar and string carrier does.
578impl<T> UpcastFrom<Option<T>> for JsValue where JsValue: UpcastFrom<T> {}
579
580/// Pointers in a `Nullable` cross as JS numbers with the `f64` sentinels, as
581/// they do in an `Option`.
582macro_rules! nullable_ptr_abi {
583    ($($t:ty),*) => ($(
584        impl<T> MaybeIntoWasmAbi for $t {
585            type MaybeAbi = f64;
586
587            #[inline]
588            fn into_maybe_abi(self) -> f64 {
589                self as usize as f64
590            }
591
592            #[inline]
593            fn none() -> f64 {
594                F64_ABI_OPTION_SENTINEL
595            }
596        }
597
598        impl<T> NullableIntoWasmAbi for $t {
599            #[inline]
600            fn null() -> f64 {
601                F64_ABI_NULL_SENTINEL
602            }
603        }
604
605        impl<T> MaybeFromWasmAbi for $t {
606            type MaybeAbi = f64;
607
608            #[inline]
609            unsafe fn from_maybe_abi(js: f64) -> Self {
610                js as usize as $t
611            }
612
613            #[inline]
614            fn is_none(js: &f64) -> bool {
615                *js == F64_ABI_OPTION_SENTINEL
616            }
617        }
618
619        impl<T> NullableFromWasmAbi for $t {
620            #[inline]
621            fn is_null(js: &f64) -> bool {
622                *js == F64_ABI_NULL_SENTINEL
623            }
624        }
625    )*)
626}
627
628nullable_ptr_abi!(*const T, *mut T);
629
630impl<T> IntoWasmAbi for *mut T {
631    type Abi = WasmWordRepr;
632
633    #[inline]
634    fn into_abi(self) -> Self::Abi {
635        self as usize as WasmWordRepr
636    }
637}
638
639impl<T> FromWasmAbi for *mut T {
640    type Abi = WasmWordRepr;
641
642    #[inline]
643    unsafe fn from_abi(js: Self::Abi) -> *mut T {
644        js as usize as *mut T
645    }
646}
647
648impl<T> IntoWasmAbi for NonNull<T> {
649    type Abi = WasmWordRepr;
650
651    #[inline]
652    fn into_abi(self) -> Self::Abi {
653        self.as_ptr() as usize as WasmWordRepr
654    }
655}
656
657impl<T> OptionIntoWasmAbi for NonNull<T> {
658    #[inline]
659    fn none() -> Self::Abi {
660        0 as WasmWordRepr
661    }
662}
663
664impl<T> FromWasmAbi for NonNull<T> {
665    type Abi = WasmWordRepr;
666
667    #[inline]
668    unsafe fn from_abi(js: Self::Abi) -> Self {
669        // SAFETY: Checked in bindings.
670        NonNull::new_unchecked(js as usize as *mut T)
671    }
672}
673
674impl<T> OptionFromWasmAbi for NonNull<T> {
675    #[inline]
676    fn is_none(js: &Self::Abi) -> bool {
677        *js == 0 as WasmWordRepr
678    }
679}
680
681impl IntoWasmAbi for JsValue {
682    type Abi = u32;
683
684    #[inline]
685    fn into_abi(self) -> u32 {
686        let ret = self.idx;
687        mem::forget(self);
688        ret
689    }
690}
691
692impl FromWasmAbi for JsValue {
693    type Abi = u32;
694
695    #[inline]
696    unsafe fn from_abi(js: u32) -> JsValue {
697        JsValue::_new(js)
698    }
699}
700
701impl IntoWasmAbi for &JsValue {
702    type Abi = u32;
703
704    #[inline]
705    fn into_abi(self) -> u32 {
706        self.idx
707    }
708}
709
710impl RefFromWasmAbi for JsValue {
711    type Abi = u32;
712    type Anchor = ManuallyDrop<JsValue>;
713
714    #[inline]
715    unsafe fn ref_from_abi(js: u32) -> Self::Anchor {
716        ManuallyDrop::new(JsValue::_new(js))
717    }
718}
719
720impl LongRefFromWasmAbi for JsValue {
721    type Abi = u32;
722    type Anchor = JsValue;
723
724    #[inline]
725    unsafe fn long_ref_from_abi(js: u32) -> Self::Anchor {
726        Self::from_abi(js)
727    }
728}
729
730impl OptionIntoWasmAbi for JsValue {
731    #[inline]
732    fn none() -> u32 {
733        crate::__rt::JSIDX_UNDEFINED
734    }
735}
736
737impl OptionIntoWasmAbi for &JsValue {
738    #[inline]
739    fn none() -> u32 {
740        crate::__rt::JSIDX_UNDEFINED
741    }
742}
743
744impl OptionFromWasmAbi for JsValue {
745    #[inline]
746    fn is_none(js: &u32) -> bool {
747        unsafe { Self::ref_from_abi(*js) }.is_undefined()
748    }
749}
750
751impl_nullable_into_shared_abi!(null = crate::__rt::JSIDX_NULL; [] JsValue);
752impl_nullable_into_shared_abi!(null = crate::__rt::JSIDX_NULL; [] &JsValue);
753// The glue hands `null` over as the fixed handle, so this is an index test
754// rather than a call into JS; a `null` that did arrive in its own slot is an
755// owned `Value` and is dropped as one.
756impl_nullable_from_shared_abi!(is_null = |js| *js == crate::__rt::JSIDX_NULL; [] JsValue);
757
758/// A spare value in `T`'s own ABI is the common case, so `OptionIntoWasmAbi`
759/// supplies the `Option<T>` ABI for every such type; a type without one
760/// implements `MaybeIntoWasmAbi` itself with a wider `MaybeAbi`.
761impl<T: OptionIntoWasmAbi> MaybeIntoWasmAbi for T {
762    type MaybeAbi = T::Abi;
763
764    #[inline]
765    fn into_maybe_abi(self) -> T::Abi {
766        self.into_abi()
767    }
768
769    #[inline]
770    fn none() -> T::Abi {
771        <T as OptionIntoWasmAbi>::none()
772    }
773}
774
775impl<T: OptionFromWasmAbi> MaybeFromWasmAbi for T {
776    type MaybeAbi = T::Abi;
777
778    #[inline]
779    unsafe fn from_maybe_abi(js: T::Abi) -> Self {
780        T::from_abi(js)
781    }
782
783    #[inline]
784    unsafe fn try_from_maybe_abi(js: T::Abi) -> Result<Self, &'static str> {
785        T::try_from_abi(js)
786    }
787
788    #[inline]
789    fn is_none(js: &T::Abi) -> bool {
790        <T as OptionFromWasmAbi>::is_none(js)
791    }
792}
793
794impl<T: MaybeIntoWasmAbi> IntoWasmAbi for Option<T> {
795    type Abi = T::MaybeAbi;
796
797    #[inline]
798    fn into_abi(self) -> T::MaybeAbi {
799        match self {
800            None => T::none(),
801            Some(me) => me.into_maybe_abi(),
802        }
803    }
804}
805
806impl<T: MaybeFromWasmAbi> FromWasmAbi for Option<T> {
807    type Abi = T::MaybeAbi;
808
809    #[inline]
810    unsafe fn from_abi(js: T::MaybeAbi) -> Self {
811        if T::is_none(&js) {
812            None
813        } else {
814            Some(T::from_maybe_abi(js))
815        }
816    }
817
818    #[inline]
819    unsafe fn try_from_abi(js: T::MaybeAbi) -> Result<Self, &'static str> {
820        if T::is_none(&js) {
821            Ok(None)
822        } else {
823            T::try_from_maybe_abi(js).map(Some)
824        }
825    }
826}
827
828impl<T: NullableIntoWasmAbi> IntoWasmAbi for Nullable<T> {
829    type Abi = T::MaybeAbi;
830
831    #[inline]
832    fn into_abi(self) -> T::MaybeAbi {
833        match self {
834            Nullable::Null => T::null(),
835            Nullable::Value(me) => me.into_maybe_abi(),
836        }
837    }
838}
839
840/// `Option<Nullable<T>>` is `None` for `T`'s `undefined` ABI value.
841impl<T: NullableIntoWasmAbi> OptionIntoWasmAbi for Nullable<T> {
842    #[inline]
843    fn none() -> T::MaybeAbi {
844        T::none()
845    }
846}
847
848impl<T: NullableFromWasmAbi> FromWasmAbi for Nullable<T> {
849    type Abi = T::MaybeAbi;
850
851    #[inline]
852    unsafe fn from_abi(js: T::MaybeAbi) -> Self {
853        if T::is_null(&js) {
854            Nullable::Null
855        } else {
856            Nullable::Value(T::from_maybe_abi(js))
857        }
858    }
859
860    #[inline]
861    unsafe fn try_from_abi(js: T::MaybeAbi) -> Result<Self, &'static str> {
862        if T::is_null(&js) {
863            Ok(Nullable::Null)
864        } else {
865            T::try_from_maybe_abi(js).map(Nullable::Value)
866        }
867    }
868}
869
870/// `T`'s `undefined` test may cover its `null` sentinel too, as a slice's
871/// does with the null pointer, so `Null` is ruled out first.
872impl<T: NullableFromWasmAbi> OptionFromWasmAbi for Nullable<T> {
873    #[inline]
874    fn is_none(js: &T::MaybeAbi) -> bool {
875        !T::is_null(js) && T::is_none(js)
876    }
877}
878
879unsafe impl<T: ErasableGeneric> ErasableGeneric for Nullable<T> {
880    type Repr = Nullable<<T as ErasableGeneric>::Repr>;
881}
882
883impl<T, Target> UpcastFrom<Nullable<T>> for Nullable<Target> where Target: UpcastFrom<T> {}
884// An `Option<T>` reads `null` as `None`, so every value of a `Nullable<T>` is one
885// of an `Option<T>`. This is the only `Nullable` to `Option` rule coherence
886// allows, so `Nullable<T>` reaches `Option<Nullable<T>>` through it once `T`
887// wraps into `Nullable`.
888impl<T, Target> UpcastFrom<Nullable<T>> for Option<Target> where Target: UpcastFrom<T> {}
889impl<T, Target> UpcastFrom<Nullable<T>> for JsOption<Nullable<Target>> where Target: UpcastFrom<T> {}
890impl<T, Target> UpcastFrom<Nullable<T>> for JsNullable<Nullable<Target>> where Target: UpcastFrom<T> {}
891impl<T> UpcastFrom<Nullable<T>> for JsValue where JsValue: UpcastFrom<T> {}
892
893impl<T: Promising> Promising for Option<T> {
894    type Resolution = Option<<T as Promising>::Resolution>;
895}
896
897impl<T: Promising> Promising for Nullable<T> {
898    type Resolution = Nullable<<T as Promising>::Resolution>;
899}
900
901impl<T: IntoWasmAbi> IntoWasmAbi for Clamped<T> {
902    type Abi = T::Abi;
903
904    #[inline]
905    fn into_abi(self) -> Self::Abi {
906        self.0.into_abi()
907    }
908}
909
910impl<T: FromWasmAbi> FromWasmAbi for Clamped<T> {
911    type Abi = T::Abi;
912
913    #[inline]
914    unsafe fn from_abi(js: T::Abi) -> Self {
915        Clamped(T::from_abi(js))
916    }
917
918    #[inline]
919    unsafe fn try_from_abi(js: T::Abi) -> Result<Self, &'static str> {
920        T::try_from_abi(js).map(Clamped)
921    }
922}
923
924impl IntoWasmAbi for () {
925    type Abi = ();
926
927    #[inline]
928    fn into_abi(self) {
929        self
930    }
931}
932
933impl FromWasmAbi for () {
934    type Abi = ();
935
936    #[inline]
937    unsafe fn from_abi(_js: ()) {}
938}
939
940impl Promising for () {
941    type Resolution = Undefined;
942}
943
944impl UpcastFrom<()> for JsValue {}
945impl UpcastFrom<()> for () {}
946// `()` crosses as `undefined`, which an `Option<T>` reads as `None`.
947impl<T> UpcastFrom<()> for Option<T> {}
948
949unsafe impl ErasableGeneric for () {
950    type Repr = ();
951}
952
953impl<T: WasmAbi<Prim3 = (), Prim4 = ()>> WasmAbi for Result<T, u32> {
954    type Prim1 = T::Prim1;
955    type Prim2 = T::Prim2;
956    // The order of primitives here is such that we can pop() the possible error
957    // first, deal with it and move on. Later primitives are popped off the
958    // stack first.
959    /// If this `Result` is an `Err`, the error value.
960    type Prim3 = u32;
961    /// Whether this `Result` is an `Err`.
962    type Prim4 = u32;
963
964    #[inline]
965    fn split(self) -> (T::Prim1, T::Prim2, u32, u32) {
966        match self {
967            Ok(value) => {
968                let (prim1, prim2, (), ()) = value.split();
969                (prim1, prim2, 0, 0)
970            }
971            Err(err) => (Default::default(), Default::default(), err, 1),
972        }
973    }
974
975    #[inline]
976    fn join(prim1: T::Prim1, prim2: T::Prim2, err: u32, is_err: u32) -> Self {
977        if is_err == 0 {
978            Ok(T::join(prim1, prim2, (), ()))
979        } else {
980            Err(err)
981        }
982    }
983}
984
985impl<T, E> ReturnWasmAbi for Result<T, E>
986where
987    T: IntoWasmAbi,
988    E: Into<JsValue>,
989    T::Abi: WasmAbi<Prim3 = (), Prim4 = ()>,
990{
991    type Abi = Result<T::Abi, u32>;
992
993    #[inline]
994    fn return_abi(self) -> Self::Abi {
995        match self {
996            Ok(v) => Ok(v.into_abi()),
997            Err(e) => {
998                let jsval = e.into();
999                Err(jsval.into_abi())
1000            }
1001        }
1002    }
1003}
1004
1005unsafe impl<T: ErasableGeneric, E: ErasableGeneric> ErasableGeneric for Result<T, E> {
1006    type Repr = Result<<T as ErasableGeneric>::Repr, <E as ErasableGeneric>::Repr>;
1007}
1008
1009impl<T: Promising, E> Promising for Result<T, E> {
1010    type Resolution = Result<<T as Promising>::Resolution, E>;
1011}
1012
1013impl<T, E, TargetT, TargetE> UpcastFrom<Result<T, E>> for Result<TargetT, TargetE>
1014where
1015    TargetT: UpcastFrom<T>,
1016    TargetE: UpcastFrom<E>,
1017{
1018}
1019impl<T, E, TargetT, TargetE> UpcastFrom<Result<T, E>> for JsOption<Result<TargetT, TargetE>>
1020where
1021    TargetT: UpcastFrom<T>,
1022    TargetE: UpcastFrom<E>,
1023{
1024}
1025impl<T, E, TargetT, TargetE> UpcastFrom<Result<T, E>> for JsNullable<Result<TargetT, TargetE>>
1026where
1027    TargetT: UpcastFrom<T>,
1028    TargetE: UpcastFrom<E>,
1029{
1030}
1031
1032unsafe impl ErasableGeneric for JsError {
1033    type Repr = JsValue;
1034}
1035
1036impl IntoWasmAbi for JsError {
1037    type Abi = <JsValue as IntoWasmAbi>::Abi;
1038
1039    fn into_abi(self) -> Self::Abi {
1040        self.value.into_abi()
1041    }
1042}
1043
1044// `JsError` is `#[repr(transparent)]` over `JsValue`
1045impl FromWasmAbi for JsError {
1046    type Abi = <JsValue as FromWasmAbi>::Abi;
1047
1048    #[inline]
1049    unsafe fn from_abi(js: Self::Abi) -> Self {
1050        JsError {
1051            value: JsValue::from_abi(js),
1052        }
1053    }
1054}
1055
1056impl Promising for JsError {
1057    type Resolution = JsError;
1058}
1059
1060impl UpcastFrom<JsError> for JsValue {}
1061impl UpcastFrom<JsError> for JsOption<JsValue> {}
1062impl UpcastFrom<JsError> for JsNullable<JsValue> {}
1063impl UpcastFrom<JsError> for JsError {}
1064
1065/// The compat form of an owned vector: an in-place sequence of `JsValue`
1066/// handles, converted to or from `T` in Rust. The released `Vec<String>`,
1067/// `Vec`s of exported structs and numeric enums, and third-party impls cross
1068/// this way. It has no new uses: an element whose single value crosses
1069/// without calling into wasm is declared as an encoded sequence instead.
1070///
1071/// # ⚠️ Unstable
1072///
1073/// This is part of the internal [`convert`](crate::convert) module, **no
1074/// stability guarantees** are provided. Use at your own risk. See its
1075/// documentation for more details.
1076// Note: this can't take `&[T]` because the `Into<JsValue>` impl needs
1077// ownership of `T`.
1078pub fn js_value_vector_into_abi<T: Into<JsValue>>(
1079    vector: Box<[T]>,
1080) -> <Box<[JsValue]> as IntoWasmAbi>::Abi {
1081    let js_vals: Box<[JsValue]> = vector.into_vec().into_iter().map(|x| x.into()).collect();
1082
1083    js_vals.into_abi()
1084}
1085
1086/// The mirror of [`js_value_vector_into_abi`], checking each element with
1087/// [`TryFromJsValue`].
1088///
1089/// # ⚠️ Unstable
1090///
1091/// This is part of the internal [`convert`](crate::convert) module, **no
1092/// stability guarantees** are provided. Use at your own risk. See its
1093/// documentation for more details.
1094pub unsafe fn js_value_vector_from_abi<T: TryFromJsValue>(
1095    js: <Box<[JsValue]> as FromWasmAbi>::Abi,
1096) -> Box<[T]> {
1097    // Thrown directly, rather than inside the iterator chain or a closure, to
1098    // keep the function that took the `Vec` within the debug-mode error
1099    // stack's frame limit.
1100    match try_js_value_vector_from_abi(js) {
1101        Ok(result) => result,
1102        Err(msg) => throw_str(msg),
1103    }
1104}
1105
1106/// The fallible form of [`js_value_vector_from_abi`].
1107///
1108/// Collecting stops at the first element of the wrong type and drops
1109/// everything Rust owns: the buffer, the handles not yet converted, the
1110/// rejected handle and the elements converted so far.
1111///
1112/// # ⚠️ Unstable
1113///
1114/// This is part of the internal [`convert`](crate::convert) module, **no
1115/// stability guarantees** are provided. Use at your own risk. See its
1116/// documentation for more details.
1117pub unsafe fn try_js_value_vector_from_abi<T: TryFromJsValue>(
1118    js: <Box<[JsValue]> as FromWasmAbi>::Abi,
1119) -> Result<Box<[T]>, &'static str> {
1120    <Vec<JsValue> as FromWasmAbi>::from_abi(js)
1121        .into_iter()
1122        .map(|value| T::try_from_js_value(value).map_err(|_| crate::__rt::WRONG_TYPE_ERROR))
1123        .collect()
1124}