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