1 | use core::borrow::Borrow; |
2 | use core::ops::{Deref, DerefMut}; |
3 | |
4 | use crate::describe::*; |
5 | use 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`. |
11 | pub 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`. |
25 | pub 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`. |
45 | pub 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'. |
78 | pub 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. |
90 | pub 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>`. |
102 | pub 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>`. |
114 | pub 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. |
131 | pub unsafe trait WasmPrimitive: Default {} |
132 | |
133 | unsafe impl WasmPrimitive for u32 {} |
134 | unsafe impl WasmPrimitive for i32 {} |
135 | unsafe impl WasmPrimitive for u64 {} |
136 | unsafe impl WasmPrimitive for i64 {} |
137 | unsafe impl WasmPrimitive for f32 {} |
138 | unsafe impl WasmPrimitive for f64 {} |
139 | unsafe 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. |
157 | pub 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" |
177 | pub 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 | |
186 | impl<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 | |
195 | if_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)] |
226 | pub struct WasmRet<T: WasmAbi> { |
227 | prim1: T::Prim1, |
228 | prim2: T::Prim2, |
229 | prim3: T::Prim3, |
230 | prim4: T::Prim4, |
231 | } |
232 | |
233 | impl<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. |
247 | impl<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. |
261 | pub 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 | |