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}