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 OptionIntoWasmAbi for &JsValue {
476    #[inline]
477    fn none() -> u32 {
478        crate::__rt::JSIDX_UNDEFINED
479    }
480}
481
482impl OptionFromWasmAbi for JsValue {
483    #[inline]
484    fn is_none(js: &u32) -> bool {
485        unsafe { __wbindgen_object_is_undefined(*js) }
486    }
487}
488
489impl<T: OptionIntoWasmAbi> IntoWasmAbi for Option<T> {
490    type Abi = T::Abi;
491
492    #[inline]
493    fn into_abi(self) -> T::Abi {
494        match self {
495            None => T::none(),
496            Some(me) => me.into_abi(),
497        }
498    }
499}
500
501impl<T: OptionFromWasmAbi> FromWasmAbi for Option<T> {
502    type Abi = T::Abi;
503
504    #[inline]
505    unsafe fn from_abi(js: T::Abi) -> Self {
506        if T::is_none(&js) {
507            None
508        } else {
509            Some(T::from_abi(js))
510        }
511    }
512}
513
514impl<T: IntoWasmAbi> IntoWasmAbi for Clamped<T> {
515    type Abi = T::Abi;
516
517    #[inline]
518    fn into_abi(self) -> Self::Abi {
519        self.0.into_abi()
520    }
521}
522
523impl<T: FromWasmAbi> FromWasmAbi for Clamped<T> {
524    type Abi = T::Abi;
525
526    #[inline]
527    unsafe fn from_abi(js: T::Abi) -> Self {
528        Clamped(T::from_abi(js))
529    }
530}
531
532impl IntoWasmAbi for () {
533    type Abi = ();
534
535    #[inline]
536    fn into_abi(self) {
537        self
538    }
539}
540
541impl<T: WasmAbi<Prim3 = (), Prim4 = ()>> WasmAbi for Result<T, u32> {
542    type Prim1 = T::Prim1;
543    type Prim2 = T::Prim2;
544    // The order of primitives here is such that we can pop() the possible error
545    // first, deal with it and move on. Later primitives are popped off the
546    // stack first.
547    /// If this `Result` is an `Err`, the error value.
548    type Prim3 = u32;
549    /// Whether this `Result` is an `Err`.
550    type Prim4 = u32;
551
552    #[inline]
553    fn split(self) -> (T::Prim1, T::Prim2, u32, u32) {
554        match self {
555            Ok(value) => {
556                let (prim1, prim2, (), ()) = value.split();
557                (prim1, prim2, 0, 0)
558            }
559            Err(err) => (Default::default(), Default::default(), err, 1),
560        }
561    }
562
563    #[inline]
564    fn join(prim1: T::Prim1, prim2: T::Prim2, err: u32, is_err: u32) -> Self {
565        if is_err == 0 {
566            Ok(T::join(prim1, prim2, (), ()))
567        } else {
568            Err(err)
569        }
570    }
571}
572
573impl<T, E> ReturnWasmAbi for Result<T, E>
574where
575    T: IntoWasmAbi,
576    E: Into<JsValue>,
577    T::Abi: WasmAbi<Prim3 = (), Prim4 = ()>,
578{
579    type Abi = Result<T::Abi, u32>;
580
581    #[inline]
582    fn return_abi(self) -> Self::Abi {
583        match self {
584            Ok(v) => Ok(v.into_abi()),
585            Err(e) => {
586                let jsval = e.into();
587                Err(jsval.into_abi())
588            }
589        }
590    }
591}
592
593impl IntoWasmAbi for JsError {
594    type Abi = <JsValue as IntoWasmAbi>::Abi;
595
596    fn into_abi(self) -> Self::Abi {
597        self.value.into_abi()
598    }
599}
600
601/// # ⚠️ Unstable
602///
603/// This is part of the internal [`convert`](crate::convert) module, **no
604/// stability guarantees** are provided. Use at your own risk. See its
605/// documentation for more details.
606// Note: this can't take `&[T]` because the `Into<JsValue>` impl needs
607// ownership of `T`.
608pub fn js_value_vector_into_abi<T: Into<JsValue>>(
609    vector: Box<[T]>,
610) -> <Box<[JsValue]> as IntoWasmAbi>::Abi {
611    let js_vals: Box<[JsValue]> = vector.into_vec().into_iter().map(|x| x.into()).collect();
612
613    js_vals.into_abi()
614}
615
616/// # ⚠️ Unstable
617///
618/// This is part of the internal [`convert`](crate::convert) module, **no
619/// stability guarantees** are provided. Use at your own risk. See its
620/// documentation for more details.
621pub unsafe fn js_value_vector_from_abi<T: TryFromJsValue>(
622    js: <Box<[JsValue]> as FromWasmAbi>::Abi,
623) -> Box<[T]> {
624    let js_vals = <Vec<JsValue> as FromWasmAbi>::from_abi(js);
625
626    let mut result = Vec::with_capacity(js_vals.len());
627    for value in js_vals {
628        // We push elements one-by-one instead of using `collect` in order to improve
629        // error messages. When using `collect`, this `expect_throw` is buried in a
630        // giant chain of internal iterator functions, which results in the actual
631        // function that takes this `Vec` falling off the end of the call stack.
632        // So instead, make sure to call it directly within this function.
633        //
634        // This is only a problem in debug mode. Since this is the browser's error stack
635        // we're talking about, it can only see functions that actually make it to the
636        // final Wasm binary (i.e., not inlined functions). All of those internal
637        // iterator functions get inlined in release mode, and so they don't show up.
638        result.push(
639            T::try_from_js_value(value).expect_throw("array contains a value of the wrong type"),
640        );
641    }
642    result.into_boxed_slice()
643}