Skip to main content

wry_bindgen/convert/
impls.rs

1use crate::__rt::JsRef;
2use crate::{JsCast, JsValue};
3use core::marker::PhantomData;
4
5use super::{
6    FromWasmAbi, IntoWasmAbi, JsGeneric, OptionFromWasmAbi, OptionIntoWasmAbi, RefFromWasmAbi,
7    UpcastFrom, WasmAbi,
8};
9
10// `IntoWasmAbi`/`FromWasmAbi` are implemented per-type, mirroring upstream
11// wasm-bindgen, rather than through a single blanket over `BinaryEncode`. This
12// keeps `Result` outside `IntoWasmAbi`, which is what lets `ReturnWasmAbi` carve
13// out `Result` for throwing returns without a coherence conflict.
14//
15// Every JS heap value is `JsGeneric`, which already requires the wire traits, so
16// one blanket covers js-sys/web-sys and every generated `extern` type.
17impl<T: JsGeneric> IntoWasmAbi for T {}
18impl<T: JsGeneric> FromWasmAbi for T {}
19
20// The value types that are not `JsGeneric` are enumerated explicitly.
21macro_rules! value_wasm_abi {
22    ($($ty:ty),* $(,)?) => {$(
23        impl IntoWasmAbi for $ty {}
24        impl FromWasmAbi for $ty {}
25    )*};
26}
27
28value_wasm_abi!(
29    (),
30    bool,
31    char,
32    f32,
33    f64,
34    usize,
35    isize,
36    alloc::string::String,
37    i8,
38    i16,
39    i32,
40    i64,
41    i128,
42    u8,
43    u16,
44    u32,
45    u64,
46    u128,
47);
48
49// Value types upcast to themselves (identity) and widen to `JsValue`, so a
50// closure that yields/accepts a value type can be viewed through the wider JS
51// type (e.g. `dyn Fn() -> i32` -> `dyn Fn() -> JsValue`). The wire encoding is
52// unchanged - a primitive already rides the boundary as its JS value - so these
53// markers only authorize the type-level reinterpretation.
54macro_rules! value_upcast {
55    ($($ty:ty),* $(,)?) => {$(
56        impl UpcastFrom<$ty> for $ty {}
57        impl UpcastFrom<$ty> for JsValue {}
58    )*};
59}
60
61value_upcast!(
62    bool, char, f32, f64, usize, isize, i8, i16, i32, i64, i128, u8, u16, u32, u64, u128,
63);
64
65impl<T: crate::__rt::BinaryEncode + crate::__rt::EncodeTypeDef> IntoWasmAbi
66    for core::option::Option<T>
67{
68}
69
70impl<T: crate::__rt::BinaryDecode + crate::__rt::EncodeTypeDef> FromWasmAbi
71    for core::option::Option<T>
72{
73}
74
75// A shared `&JsValue` flows across the boundary by id, matching wasm-bindgen's
76// `IntoWasmAbi for &JsValue`.
77impl IntoWasmAbi for &JsValue {}
78
79impl<T> OptionIntoWasmAbi for T where T: IntoWasmAbi {}
80impl<T> OptionFromWasmAbi for T where T: FromWasmAbi {}
81impl<T: ?Sized> WasmAbi for T {}
82impl<T: ?Sized> RefFromWasmAbi for T {}
83
84impl UpcastFrom<JsValue> for JsValue {}
85
86/// Anchor type for JsCast references.
87///
88/// This holds a `JsValue` and provides a reference to the target type `T`
89/// through the `JsCast` trait.
90pub struct JsCastAnchor<T: JsCast> {
91    value: JsValue,
92    _marker: PhantomData<T>,
93}
94
95impl<T: JsCast> core::ops::Deref for JsCastAnchor<T> {
96    type Target = T;
97
98    fn deref(&self) -> &Self::Target {
99        T::unchecked_from_js_ref(&self.value)
100    }
101}
102
103impl<T: JsCast> JsCastAnchor<T> {
104    /// Anchor the next borrowed reference JS pushed onto its borrow stack. A
105    /// borrowed arg arrives without a heap id, so the value is taken by position
106    /// from the runtime's borrow stack.
107    #[doc(hidden)]
108    pub fn next_borrowed() -> Self {
109        JsCastAnchor {
110            value: JsValue::from_ref(JsRef::next_borrowed_ref()),
111            _marker: PhantomData,
112        }
113    }
114}