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