mirror of
https://github.com/fluencelabs/wasm-bindgen
synced 2025-06-01 07:01:22 +00:00
Add a JsCast
trait specified in [RFC 2]
[RFC 2]: https://github.com/rustwasm/rfcs/pull/2
This commit is contained in:
parent
9b65e57585
commit
bea07abd0f
165
src/cast.rs
Normal file
165
src/cast.rs
Normal file
@ -0,0 +1,165 @@
|
||||
use JsValue;
|
||||
|
||||
/// A trait for checked and unchecked casting between JS types.
|
||||
///
|
||||
/// Specified [in an RFC][rfc] this trait is intended to provide support for
|
||||
/// casting JS values between differnet types of one another. In JS there aren't
|
||||
/// many static types but we've ascribed JS values with static types in Rust,
|
||||
/// yet they often need to be switched to other types temporarily! This trait
|
||||
/// provides both checked and unchecked casting into various kinds of values.
|
||||
///
|
||||
/// This trait is automatically implemented for any type imported in a
|
||||
/// `#[wasm_bindgen]` `extern` block.
|
||||
///
|
||||
/// [rfc]: https://github.com/rustwasm/rfcs/pull/2
|
||||
pub trait JsCast
|
||||
where
|
||||
Self: AsRef<JsValue> + AsMut<JsValue> + Into<JsValue>,
|
||||
{
|
||||
/// Test whether this JS value is an instance of the type `T`.
|
||||
///
|
||||
/// This commit performs a dynamic check (at runtime) using the JS
|
||||
/// `instanceof` operator. This method returns `self instanceof T`.
|
||||
fn is_instance_of<T>(&self) -> bool
|
||||
where
|
||||
T: JsCast,
|
||||
{
|
||||
T::instanceof(self.as_ref())
|
||||
}
|
||||
|
||||
/// Performs a dynamic cast (checked at runtime) of this value into the
|
||||
/// target type `T`.
|
||||
///
|
||||
/// This method will return `Err(self)` is `self.is_instance_of::<T>()`
|
||||
/// returns `false`, and otherwise it will return `Ok(T)` manufactured with
|
||||
/// an unchecked cast (verified safe via the `instanceof` operation).
|
||||
fn dyn_into<T>(self) -> Result<T, Self>
|
||||
where
|
||||
T: JsCast,
|
||||
{
|
||||
if self.is_instance_of::<T>() {
|
||||
Ok(self.unchecked_into())
|
||||
} else {
|
||||
Err(self)
|
||||
}
|
||||
}
|
||||
|
||||
/// Performs a dynamic cast (checked at runtime) of this value into the
|
||||
/// target type `T`.
|
||||
///
|
||||
/// This method will return `None` is `self.is_instance_of::<T>()`
|
||||
/// returns `false`, and otherwise it will return `Some(&T)` manufactured
|
||||
/// with an unchecked cast (verified safe via the `instanceof` operation).
|
||||
fn dyn_ref<T>(&self) -> Option<&T>
|
||||
where
|
||||
T: JsCast,
|
||||
{
|
||||
if self.is_instance_of::<T>() {
|
||||
Some(self.unchecked_ref())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Performs a dynamic cast (checked at runtime) of this value into the
|
||||
/// target type `T`.
|
||||
///
|
||||
/// This method will return `None` is `self.is_instance_of::<T>()`
|
||||
/// returns `false`, and otherwise it will return `Some(&mut T)`
|
||||
/// manufactured with an unchecked cast (verified safe via the `instanceof`
|
||||
/// operation).
|
||||
fn dyn_mut<T>(&mut self) -> Option<&mut T>
|
||||
where
|
||||
T: JsCast,
|
||||
{
|
||||
if self.is_instance_of::<T>() {
|
||||
Some(self.unchecked_mut())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Performs a zero-cost unchecked cast into the specified type.
|
||||
///
|
||||
/// This method will convert the `self` value to the type `T`, where both
|
||||
/// `self` and `T` are simple wrappers around `JsValue`. This method **does
|
||||
/// not check whether `self` is an instance of `T`**. If used incorrectly
|
||||
/// then this method may cause runtime exceptions in both Rust and JS, this
|
||||
/// shoudl be used with caution.
|
||||
fn unchecked_into<T>(self) -> T
|
||||
where
|
||||
T: JsCast,
|
||||
{
|
||||
T::unchecked_from_js(self.into())
|
||||
}
|
||||
|
||||
/// Performs a zero-cost unchecked cast into a reference to the specified
|
||||
/// type.
|
||||
///
|
||||
/// This method will convert the `self` value to the type `T`, where both
|
||||
/// `self` and `T` are simple wrappers around `JsValue`. This method **does
|
||||
/// not check whether `self` is an instance of `T`**. If used incorrectly
|
||||
/// then this method may cause runtime exceptions in both Rust and JS, this
|
||||
/// shoudl be used with caution.
|
||||
///
|
||||
/// This method, unlike `unchecked_into`, does not consume ownership of
|
||||
/// `self` and instead works over a shared reference.
|
||||
fn unchecked_ref<T>(&self) -> &T
|
||||
where
|
||||
T: JsCast,
|
||||
{
|
||||
T::unchecked_from_js_ref(self.as_ref())
|
||||
}
|
||||
|
||||
/// Performs a zero-cost unchecked cast into a mutable reference to the
|
||||
/// specified type.
|
||||
///
|
||||
/// This method will convert the `self` value to the type `T`, where both
|
||||
/// `self` and `T` are simple wrappers around `JsValue`. This method **does
|
||||
/// not check whether `self` is an instance of `T`**. If used incorrectly
|
||||
/// then this method may cause runtime exceptions in both Rust and JS, this
|
||||
/// shoudl be used with caution.
|
||||
///
|
||||
/// This method, unlike `unchecked_into`, does not consume ownership of
|
||||
/// `self` and instead works over a utable reference.
|
||||
fn unchecked_mut<T>(&mut self) -> &mut T
|
||||
where
|
||||
T: JsCast,
|
||||
{
|
||||
T::unchecked_from_js_mut(self.as_mut())
|
||||
}
|
||||
|
||||
/// Performs a dynamic `instanceof` check to see whether the `JsValue`
|
||||
/// provided is an instance of this type.
|
||||
///
|
||||
/// This is intended to be an internal implementation detail, you likely
|
||||
/// won't need to call this.
|
||||
fn instanceof(val: &JsValue) -> bool;
|
||||
|
||||
/// Performs a zero-cost unchecked conversion from a `JsValue` into an
|
||||
/// instance of `Self`
|
||||
///
|
||||
/// This is intended to be an internal implementation detail, you likely
|
||||
/// won't need to call this.
|
||||
fn unchecked_from_js(val: JsValue) -> Self;
|
||||
|
||||
/// Performs a zero-cost unchecked conversion from a `&JsValue` into an
|
||||
/// instance of `&Self`.
|
||||
///
|
||||
/// Note the safety of this method, which basically means that `Self` must
|
||||
/// be a newtype wrapper around `JsValue`.
|
||||
///
|
||||
/// This is intended to be an internal implementation detail, you likely
|
||||
/// won't need to call this.
|
||||
fn unchecked_from_js_ref(val: &JsValue) -> &Self;
|
||||
|
||||
/// Performs a zero-cost unchecked conversion from a `&mut JsValue` into an
|
||||
/// instance of `&mut Self`.
|
||||
///
|
||||
/// Note the safety of this method, which basically means that `Self` must
|
||||
/// be a newtype wrapper around `JsValue`.
|
||||
///
|
||||
/// This is intended to be an internal implementation detail, you likely
|
||||
/// won't need to call this.
|
||||
fn unchecked_from_js_mut(val: &mut JsValue) -> &mut Self;
|
||||
}
|
19
src/lib.rs
19
src/lib.rs
@ -46,6 +46,9 @@ pub mod prelude {
|
||||
pub mod convert;
|
||||
pub mod describe;
|
||||
|
||||
mod cast;
|
||||
pub use cast::JsCast;
|
||||
|
||||
if_std! {
|
||||
extern crate std;
|
||||
use std::prelude::v1::*;
|
||||
@ -347,6 +350,22 @@ impl From<bool> for JsValue {
|
||||
}
|
||||
}
|
||||
|
||||
impl JsCast for JsValue {
|
||||
// everything is a `JsValue`!
|
||||
fn instanceof(_val: &JsValue) -> bool { true }
|
||||
fn unchecked_from_js(val: JsValue) -> Self { val }
|
||||
fn unchecked_from_js_ref(val: &JsValue) -> &Self { val }
|
||||
fn unchecked_from_js_mut(val: &mut JsValue) -> &mut Self { val }
|
||||
}
|
||||
|
||||
impl AsMut<JsValue> for JsValue {
|
||||
fn as_mut(&mut self) -> &mut JsValue { self }
|
||||
}
|
||||
|
||||
impl AsRef<JsValue> for JsValue {
|
||||
fn as_ref(&self) -> &JsValue { self }
|
||||
}
|
||||
|
||||
macro_rules! numbers {
|
||||
($($n:ident)*) => ($(
|
||||
impl PartialEq<$n> for JsValue {
|
||||
|
Loading…
x
Reference in New Issue
Block a user