Remove casting to &mut T for JS casts

I discussed this with @fitzgen awhile back and this sort of casting seems
especially problematic when you have code along the lines of:

    let mut x: HtmlElement = ...;
    {
        let y: &mut JsValue = x.as_ref();
        *y = 3.into();
    }
    x.some_html_element_method();

as that will immediately throw! We didn't have a use case for mutable casting
other than consistency, so this commit removes it for now. We can possibly add
it back in later if motivated, but for now it seems reasonable to try to avoid
these sorts of pitfalls!
This commit is contained in:
Alex Crichton 2018-08-24 20:45:11 -07:00
parent 8ce7465bba
commit 9729efe50e
3 changed files with 1 additions and 75 deletions

View File

@ -618,9 +618,6 @@ impl ToTokens for ast::ImportType {
fn as_ref(&self) -> &JsValue { &self.obj }
}
impl AsMut<JsValue> for #rust_name {
fn as_mut(&mut self) -> &mut JsValue { &mut self.obj }
}
impl From<#rust_name> for JsValue {
fn from(obj: #rust_name) -> JsValue {
@ -656,12 +653,6 @@ impl ToTokens for ast::ImportType {
// wrapper around `val`
unsafe { &*(val as *const JsValue as *const #rust_name) }
}
fn unchecked_from_js_mut(val: &mut JsValue) -> &mut Self {
// Should be safe because `#rust_name` is a transparent
// wrapper around `val`
unsafe { &mut *(val as *mut JsValue as *mut #rust_name) }
}
}
()
@ -683,13 +674,6 @@ impl ToTokens for ast::ImportType {
#superclass::unchecked_from_js_ref(self.as_ref())
}
}
impl AsMut<#superclass> for #rust_name {
fn as_mut(&mut self) -> &mut #superclass {
use wasm_bindgen::JsCast;
#superclass::unchecked_from_js_mut(self.as_mut())
}
}
}).to_tokens(tokens);
}
}
@ -1191,9 +1175,6 @@ impl ToTokens for ast::Dictionary {
impl AsRef<JsValue> for #name {
fn as_ref(&self) -> &JsValue { self.obj.as_ref() }
}
impl AsMut<JsValue> for #name {
fn as_mut(&mut self) -> &mut JsValue { self.obj.as_mut() }
}
// Boundary conversion impls
impl WasmDescribe for #name {
@ -1257,10 +1238,6 @@ impl ToTokens for ast::Dictionary {
fn unchecked_from_js_ref(val: &JsValue) -> &Self {
unsafe { &*(val as *const JsValue as *const #name) }
}
fn unchecked_from_js_mut(val: &mut JsValue) -> &mut Self {
unsafe { &mut *(val as *mut JsValue as *mut #name) }
}
}
};
}).to_tokens(tokens);

View File

@ -14,7 +14,7 @@ use JsValue;
/// [rfc]: https://github.com/rustwasm/rfcs/pull/2
pub trait JsCast
where
Self: AsRef<JsValue> + AsMut<JsValue> + Into<JsValue>,
Self: AsRef<JsValue> + Into<JsValue>,
{
/// Test whether this JS value is an instance of the type `T`.
///
@ -61,24 +61,6 @@ where
}
}
/// 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 correct 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
@ -111,24 +93,6 @@ where
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
/// should 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.
///
@ -152,14 +116,4 @@ where
/// 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;
}

View File

@ -370,11 +370,6 @@ impl JsCast for 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 {