ic_wasm_bindgen/convert/
traits.rs

1use core::borrow::Borrow;
2use core::ops::{Deref, DerefMut};
3
4use crate::describe::*;
5
6/// A trait for anything that can be converted into a type that can cross the
7/// wasm ABI directly, eg `u32` or `f64`.
8///
9/// This is the opposite operation as `FromWasmAbi` and `Ref[Mut]FromWasmAbi`.
10pub trait IntoWasmAbi: WasmDescribe {
11    /// The wasm ABI type that this converts into when crossing the ABI
12    /// boundary.
13    type Abi: WasmAbi;
14
15    /// Convert `self` into `Self::Abi` so that it can be sent across the wasm
16    /// ABI boundary.
17    fn into_abi(self) -> Self::Abi;
18}
19
20/// A trait for anything that can be recovered by-value from the wasm ABI
21/// boundary, eg a Rust `u8` can be recovered from the wasm ABI `u32` type.
22///
23/// This is the by-value variant of the opposite operation as `IntoWasmAbi`.
24pub trait FromWasmAbi: WasmDescribe {
25    /// The wasm ABI type that this converts from when coming back out from the
26    /// ABI boundary.
27    type Abi: WasmAbi;
28
29    /// Recover a `Self` from `Self::Abi`.
30    ///
31    /// # Safety
32    ///
33    /// This is only safe to call when -- and implementations may assume that --
34    /// the supplied `Self::Abi` was previously generated by a call to `<Self as
35    /// IntoWasmAbi>::into_abi()` or the moral equivalent in JS.
36    unsafe fn from_abi(js: Self::Abi) -> Self;
37}
38
39/// A trait for anything that can be recovered as some sort of shared reference
40/// from the wasm ABI boundary.
41///
42/// This is the shared reference variant of the opposite operation as
43/// `IntoWasmAbi`.
44pub trait RefFromWasmAbi: WasmDescribe {
45    /// The wasm ABI type references to `Self` are recovered from.
46    type Abi: WasmAbi;
47
48    /// The type that holds the reference to `Self` for the duration of the
49    /// invocation of the function that has an `&Self` parameter. This is
50    /// required to ensure that the lifetimes don't persist beyond one function
51    /// call, and so that they remain anonymous.
52    type Anchor: Deref<Target = Self>;
53
54    /// Recover a `Self::Anchor` from `Self::Abi`.
55    ///
56    /// # Safety
57    ///
58    /// Same as `FromWasmAbi::from_abi`.
59    unsafe fn ref_from_abi(js: Self::Abi) -> Self::Anchor;
60}
61
62/// A version of the `RefFromWasmAbi` trait with the additional requirement
63/// that the reference must remain valid as long as the anchor isn't dropped.
64///
65/// This isn't the case for `JsValue`'s `RefFromWasmAbi` implementation. To
66/// avoid having to allocate a spot for the `JsValue` on the `JsValue` heap,
67/// the `JsValue` is instead pushed onto the `JsValue` stack, and popped off
68/// again after the function that the reference was passed to returns. So,
69/// `JsValue` has a different `LongRefFromWasmAbi` implementation that behaves
70/// the same as `FromWasmAbi`, putting the value on the heap.
71///
72/// This is needed for async functions, where the reference needs to be valid
73/// for the whole length of the `Future`, rather than the initial synchronous
74/// call.
75///
76/// 'long ref' is short for 'long-lived reference'.
77pub trait LongRefFromWasmAbi: WasmDescribe {
78    /// Same as `RefFromWasmAbi::Abi`
79    type Abi: WasmAbi;
80
81    /// Same as `RefFromWasmAbi::Anchor`
82    type Anchor: Borrow<Self>;
83
84    /// Same as `RefFromWasmAbi::ref_from_abi`
85    unsafe fn long_ref_from_abi(js: Self::Abi) -> Self::Anchor;
86}
87
88/// Dual of the `RefFromWasmAbi` trait, except for mutable references.
89pub trait RefMutFromWasmAbi: WasmDescribe {
90    /// Same as `RefFromWasmAbi::Abi`
91    type Abi: WasmAbi;
92    /// Same as `RefFromWasmAbi::Anchor`
93    type Anchor: DerefMut<Target = Self>;
94    /// Same as `RefFromWasmAbi::ref_from_abi`
95    unsafe fn ref_mut_from_abi(js: Self::Abi) -> Self::Anchor;
96}
97
98/// Indicates that this type can be passed to JS as `Option<Self>`.
99///
100/// This trait is used when implementing `IntoWasmAbi for Option<T>`.
101pub trait OptionIntoWasmAbi: IntoWasmAbi {
102    /// Returns an ABI instance indicating "none", which JS will interpret as
103    /// the `None` branch of this option.
104    ///
105    /// It should be guaranteed that the `IntoWasmAbi` can never produce the ABI
106    /// value returned here.
107    fn none() -> Self::Abi;
108}
109
110/// Indicates that this type can be received from JS as `Option<Self>`.
111///
112/// This trait is used when implementing `FromWasmAbi for Option<T>`.
113pub trait OptionFromWasmAbi: FromWasmAbi {
114    /// Tests whether the argument is a "none" instance. If so it will be
115    /// deserialized as `None`, and otherwise it will be passed to
116    /// `FromWasmAbi`.
117    fn is_none(abi: &Self::Abi) -> bool;
118}
119
120/// A trait for any type which maps to a Wasm primitive type when used in FFI
121/// (`i32`, `i64`, `f32`, or `f64`).
122///
123/// This is with the exception of `()` (and other zero-sized types), which are
124/// also allowed because they're ignored: no arguments actually get added.
125///
126/// # Safety
127///
128/// This is an unsafe trait to implement as there's no guarantee the type
129/// actually maps to a primitive type.
130pub unsafe trait WasmPrimitive: Default {}
131
132unsafe impl WasmPrimitive for u32 {}
133unsafe impl WasmPrimitive for i32 {}
134unsafe impl WasmPrimitive for u64 {}
135unsafe impl WasmPrimitive for i64 {}
136unsafe impl WasmPrimitive for f32 {}
137unsafe impl WasmPrimitive for f64 {}
138unsafe impl WasmPrimitive for () {}
139
140/// A trait which represents types that can be passed across the Wasm ABI
141/// boundary, by being split into multiple Wasm primitive types.
142///
143/// Up to 4 primitives are supported; if you don't want to use all of them, you
144/// can set the rest to `()`, which will cause them to be ignored.
145///
146/// You need to be careful how many primitives you use, however:
147/// `Result<T, JsValue>` uses up 2 primitives to store the error, and so it
148/// doesn't work if `T` uses more than 2 primitives.
149///
150/// So, if you're adding support for a type that needs 3 or more primitives and
151/// is able to be returned, you have to add another primitive here.
152///
153/// There's already one type that uses 3 primitives: `&mut [T]`. However, it
154/// can't be returned anyway, so it doesn't matter that
155/// `Result<&mut [T], JsValue>` wouldn't work.
156pub trait WasmAbi {
157    type Prim1: WasmPrimitive;
158    type Prim2: WasmPrimitive;
159    type Prim3: WasmPrimitive;
160    type Prim4: WasmPrimitive;
161
162    /// Splits this type up into primitives to be sent over the ABI.
163    fn split(self) -> (Self::Prim1, Self::Prim2, Self::Prim3, Self::Prim4);
164    /// Reconstructs this type from primitives received over the ABI.
165    fn join(prim1: Self::Prim1, prim2: Self::Prim2, prim3: Self::Prim3, prim4: Self::Prim4)
166        -> Self;
167}
168
169/// A trait representing how to interpret the return value of a function for
170/// the wasm ABI.
171///
172/// This is very similar to the `IntoWasmAbi` trait and in fact has a blanket
173/// implementation for all implementors of the `IntoWasmAbi`. The primary use
174/// case of this trait is to enable functions to return `Result`, interpreting
175/// an error as "rethrow this to JS"
176pub trait ReturnWasmAbi: WasmDescribe {
177    /// Same as `IntoWasmAbi::Abi`
178    type Abi: WasmAbi;
179
180    /// Same as `IntoWasmAbi::into_abi`, except that it may throw and never
181    /// return in the case of `Err`.
182    fn return_abi(self) -> Self::Abi;
183}
184
185impl<T: IntoWasmAbi> ReturnWasmAbi for T {
186    type Abi = T::Abi;
187
188    #[inline]
189    fn return_abi(self) -> Self::Abi {
190        self.into_abi()
191    }
192}
193
194if_std! {
195    use core::marker::Sized;
196    use std::boxed::Box;
197
198    /// Trait for element types to implement IntoWasmAbi for vectors of
199    /// themselves.
200    pub trait VectorIntoWasmAbi: WasmDescribeVector + Sized {
201        type Abi: WasmAbi;
202
203        fn vector_into_abi(vector: Box<[Self]>) -> Self::Abi;
204    }
205
206    /// Trait for element types to implement FromWasmAbi for vectors of
207    /// themselves.
208    pub trait VectorFromWasmAbi: WasmDescribeVector + Sized {
209        type Abi: WasmAbi;
210
211        unsafe fn vector_from_abi(js: Self::Abi) -> Box<[Self]>;
212    }
213}
214
215/// A repr(C) struct containing all of the primitives of a `WasmAbi` type, in
216/// order.
217///
218/// This is used as the return type of imported/exported functions. `WasmAbi`
219/// types aren't guaranteed to be FFI-safe, so we can't return them directly:
220/// instead we return this.
221///
222/// If all but one of the primitives is `()`, this corresponds to returning the
223/// remaining primitive directly, otherwise a return pointer is used.
224#[repr(C)]
225pub struct WasmRet<T: WasmAbi> {
226    prim1: T::Prim1,
227    prim2: T::Prim2,
228    prim3: T::Prim3,
229    prim4: T::Prim4,
230}
231
232impl<T: WasmAbi> From<T> for WasmRet<T> {
233    fn from(value: T) -> Self {
234        let (prim1, prim2, prim3, prim4) = value.split();
235        Self {
236            prim1,
237            prim2,
238            prim3,
239            prim4,
240        }
241    }
242}
243
244// Ideally this'd just be an `Into<T>` implementation, but unfortunately that
245// doesn't work because of the orphan rule.
246impl<T: WasmAbi> WasmRet<T> {
247    /// Joins the components of this `WasmRet` back into the type they represent.
248    pub fn join(self) -> T {
249        T::join(self.prim1, self.prim2, self.prim3, self.prim4)
250    }
251}