use core::borrow::Borrow; use core::ops::{Deref, DerefMut}; use crate::describe::*; use crate::JsValue; /// A trait for anything that can be converted into a type that can cross the /// wasm ABI directly, eg `u32` or `f64`. /// /// This is the opposite operation as `FromWasmAbi` and `Ref[Mut]FromWasmAbi`. pub trait IntoWasmAbi: WasmDescribe { /// The wasm ABI type that this converts into when crossing the ABI /// boundary. type Abi: WasmAbi; /// Convert `self` into `Self::Abi` so that it can be sent across the wasm /// ABI boundary. fn into_abi(self) -> Self::Abi; } /// A trait for anything that can be recovered by-value from the wasm ABI /// boundary, eg a Rust `u8` can be recovered from the wasm ABI `u32` type. /// /// This is the by-value variant of the opposite operation as `IntoWasmAbi`. pub trait FromWasmAbi: WasmDescribe { /// The wasm ABI type that this converts from when coming back out from the /// ABI boundary. type Abi: WasmAbi; /// Recover a `Self` from `Self::Abi`. /// /// # Safety /// /// This is only safe to call when -- and implementations may assume that -- /// the supplied `Self::Abi` was previously generated by a call to `::into_abi()` or the moral equivalent in JS. unsafe fn from_abi(js: Self::Abi) -> Self; } /// A trait for anything that can be recovered as some sort of shared reference /// from the wasm ABI boundary. /// /// This is the shared reference variant of the opposite operation as /// `IntoWasmAbi`. pub trait RefFromWasmAbi: WasmDescribe { /// The wasm ABI type references to `Self` are recovered from. type Abi: WasmAbi; /// The type that holds the reference to `Self` for the duration of the /// invocation of the function that has an `&Self` parameter. This is /// required to ensure that the lifetimes don't persist beyond one function /// call, and so that they remain anonymous. type Anchor: Deref; /// Recover a `Self::Anchor` from `Self::Abi`. /// /// # Safety /// /// Same as `FromWasmAbi::from_abi`. unsafe fn ref_from_abi(js: Self::Abi) -> Self::Anchor; } /// A version of the `RefFromWasmAbi` trait with the additional requirement /// that the reference must remain valid as long as the anchor isn't dropped. /// /// This isn't the case for `JsValue`'s `RefFromWasmAbi` implementation. To /// avoid having to allocate a spot for the `JsValue` on the `JsValue` heap, /// the `JsValue` is instead pushed onto the `JsValue` stack, and popped off /// again after the function that the reference was passed to returns. So, /// `JsValue` has a different `LongRefFromWasmAbi` implementation that behaves /// the same as `FromWasmAbi`, putting the value on the heap. /// /// This is needed for async functions, where the reference needs to be valid /// for the whole length of the `Future`, rather than the initial synchronous /// call. /// /// 'long ref' is short for 'long-lived reference'. pub trait LongRefFromWasmAbi: WasmDescribe { /// Same as `RefFromWasmAbi::Abi` type Abi: WasmAbi; /// Same as `RefFromWasmAbi::Anchor` type Anchor: Borrow; /// Same as `RefFromWasmAbi::ref_from_abi` unsafe fn long_ref_from_abi(js: Self::Abi) -> Self::Anchor; } /// Dual of the `RefFromWasmAbi` trait, except for mutable references. pub trait RefMutFromWasmAbi: WasmDescribe { /// Same as `RefFromWasmAbi::Abi` type Abi: WasmAbi; /// Same as `RefFromWasmAbi::Anchor` type Anchor: DerefMut; /// Same as `RefFromWasmAbi::ref_from_abi` unsafe fn ref_mut_from_abi(js: Self::Abi) -> Self::Anchor; } /// Indicates that this type can be passed to JS as `Option`. /// /// This trait is used when implementing `IntoWasmAbi for Option`. pub trait OptionIntoWasmAbi: IntoWasmAbi { /// Returns an ABI instance indicating "none", which JS will interpret as /// the `None` branch of this option. /// /// It should be guaranteed that the `IntoWasmAbi` can never produce the ABI /// value returned here. fn none() -> Self::Abi; } /// Indicates that this type can be received from JS as `Option`. /// /// This trait is used when implementing `FromWasmAbi for Option`. pub trait OptionFromWasmAbi: FromWasmAbi { /// Tests whether the argument is a "none" instance. If so it will be /// deserialized as `None`, and otherwise it will be passed to /// `FromWasmAbi`. fn is_none(abi: &Self::Abi) -> bool; } /// A trait for any type which maps to a Wasm primitive type when used in FFI /// (`i32`, `i64`, `f32`, or `f64`). /// /// This is with the exception of `()` (and other zero-sized types), which are /// also allowed because they're ignored: no arguments actually get added. /// /// # Safety /// /// This is an unsafe trait to implement as there's no guarantee the type /// actually maps to a primitive type. pub unsafe trait WasmPrimitive: Default {} unsafe impl WasmPrimitive for u32 {} unsafe impl WasmPrimitive for i32 {} unsafe impl WasmPrimitive for u64 {} unsafe impl WasmPrimitive for i64 {} unsafe impl WasmPrimitive for f32 {} unsafe impl WasmPrimitive for f64 {} unsafe impl WasmPrimitive for () {} /// A trait which represents types that can be passed across the Wasm ABI /// boundary, by being split into multiple Wasm primitive types. /// /// Up to 4 primitives are supported; if you don't want to use all of them, you /// can set the rest to `()`, which will cause them to be ignored. /// /// You need to be careful how many primitives you use, however: /// `Result` uses up 2 primitives to store the error, and so it /// doesn't work if `T` uses more than 2 primitives. /// /// So, if you're adding support for a type that needs 3 or more primitives and /// is able to be returned, you have to add another primitive here. /// /// There's already one type that uses 3 primitives: `&mut [T]`. However, it /// can't be returned anyway, so it doesn't matter that /// `Result<&mut [T], JsValue>` wouldn't work. pub trait WasmAbi { type Prim1: WasmPrimitive; type Prim2: WasmPrimitive; type Prim3: WasmPrimitive; type Prim4: WasmPrimitive; /// Splits this type up into primitives to be sent over the ABI. fn split(self) -> (Self::Prim1, Self::Prim2, Self::Prim3, Self::Prim4); /// Reconstructs this type from primitives received over the ABI. fn join(prim1: Self::Prim1, prim2: Self::Prim2, prim3: Self::Prim3, prim4: Self::Prim4) -> Self; } /// A trait representing how to interpret the return value of a function for /// the wasm ABI. /// /// This is very similar to the `IntoWasmAbi` trait and in fact has a blanket /// implementation for all implementors of the `IntoWasmAbi`. The primary use /// case of this trait is to enable functions to return `Result`, interpreting /// an error as "rethrow this to JS" pub trait ReturnWasmAbi: WasmDescribe { /// Same as `IntoWasmAbi::Abi` type Abi: WasmAbi; /// Same as `IntoWasmAbi::into_abi`, except that it may throw and never /// return in the case of `Err`. fn return_abi(self) -> Self::Abi; } impl ReturnWasmAbi for T { type Abi = T::Abi; #[inline] fn return_abi(self) -> Self::Abi { self.into_abi() } } if_std! { use core::marker::Sized; use std::boxed::Box; /// Trait for element types to implement IntoWasmAbi for vectors of /// themselves. pub trait VectorIntoWasmAbi: WasmDescribeVector + Sized { type Abi: WasmAbi; fn vector_into_abi(vector: Box<[Self]>) -> Self::Abi; } /// Trait for element types to implement FromWasmAbi for vectors of /// themselves. pub trait VectorFromWasmAbi: WasmDescribeVector + Sized { type Abi: WasmAbi; unsafe fn vector_from_abi(js: Self::Abi) -> Box<[Self]>; } } /// A repr(C) struct containing all of the primitives of a `WasmAbi` type, in /// order. /// /// This is used as the return type of imported/exported functions. `WasmAbi` /// types aren't guaranteed to be FFI-safe, so we can't return them directly: /// instead we return this. /// /// If all but one of the primitives is `()`, this corresponds to returning the /// remaining primitive directly, otherwise a return pointer is used. #[repr(C)] pub struct WasmRet { prim1: T::Prim1, prim2: T::Prim2, prim3: T::Prim3, prim4: T::Prim4, } impl From for WasmRet { fn from(value: T) -> Self { let (prim1, prim2, prim3, prim4) = value.split(); Self { prim1, prim2, prim3, prim4, } } } // Ideally this'd just be an `Into` implementation, but unfortunately that // doesn't work because of the orphan rule. impl WasmRet { /// Joins the components of this `WasmRet` back into the type they represent. pub fn join(self) -> T { T::join(self.prim1, self.prim2, self.prim3, self.prim4) } } /// [`TryFromJsValue`] is a trait for converting a JavaScript value ([`JsValue`]) /// into a Rust type. It is used by the [`wasm_bindgen`](wasm_bindgen_macro::wasm_bindgen) /// proc-macro to allow conversion to user types. /// /// Types implementing this trait must specify their conversion logic from /// [`JsValue`] to the Rust type, handling any potential errors that may occur /// during the conversion process. pub trait TryFromJsValue: Sized { /// The type returned in the event of a conversion error. type Error; /// Performs the conversion. fn try_from_js_value(value: JsValue) -> Result; }