wasm_bindgen/convert/
impls.rs

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