externref: Do not impl common traits, have free functions instead
If you aren't expecting `VMExternRef`'s pointer-equality semantics, then these trait implementations can be foot guns. Instead of implementing the trait, make free functions in the `VMExternRef` namespace. This way, callers have to be a little more explicit.
This commit is contained in:
@@ -77,7 +77,7 @@ use std::alloc::Layout;
|
|||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::cell::UnsafeCell;
|
use std::cell::UnsafeCell;
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::Hasher;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::ptr::{self, NonNull};
|
use std::ptr::{self, NonNull};
|
||||||
@@ -344,39 +344,43 @@ impl VMExternRef {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for VMExternRef {
|
/// Methods that would normally be trait implementations, but aren't to avoid
|
||||||
|
/// potential footguns around `VMExternRef`'s pointer-equality semantics.
|
||||||
|
///
|
||||||
|
/// Note that none of these methods are on `&self`, they all require a
|
||||||
|
/// fully-qualified `VMExternRef::foo(my_ref)` invocation.
|
||||||
|
impl VMExternRef {
|
||||||
|
/// Check whether two `VMExternRef`s point to the same inner allocation.
|
||||||
|
///
|
||||||
|
/// Note that this uses pointer-equality semantics, not structural-equality
|
||||||
|
/// semantics, and so only pointers are compared, and doesn't use any `Eq`
|
||||||
|
/// or `PartialEq` implementation of the pointed-to values.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn eq(&self, rhs: &Self) -> bool {
|
pub fn eq(a: &Self, b: &Self) -> bool {
|
||||||
ptr::eq(self.0.as_ptr() as *const _, rhs.0.as_ptr() as *const _)
|
ptr::eq(a.0.as_ptr() as *const _, b.0.as_ptr() as *const _)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl Eq for VMExternRef {}
|
/// Hash a given `VMExternRef`.
|
||||||
|
///
|
||||||
impl Hash for VMExternRef {
|
/// Note that this just hashes the pointer to the inner value, it does *not*
|
||||||
|
/// use the inner value's `Hash` implementation (if any).
|
||||||
#[inline]
|
#[inline]
|
||||||
fn hash<H>(&self, hasher: &mut H)
|
pub fn hash<H>(externref: &Self, hasher: &mut H)
|
||||||
where
|
where
|
||||||
H: Hasher,
|
H: Hasher,
|
||||||
{
|
{
|
||||||
ptr::hash(self.0.as_ptr() as *const _, hasher);
|
ptr::hash(externref.0.as_ptr() as *const _, hasher);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialOrd for VMExternRef {
|
/// Compare two `VMExternRef`s.
|
||||||
|
///
|
||||||
|
/// Note that this uses pointer-equality semantics, not structural-equality
|
||||||
|
/// semantics, and so only pointers are compared, and doesn't use any `Cmp`
|
||||||
|
/// or `PartialCmp` implementation of the pointed-to values.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
|
pub fn cmp(a: &Self, b: &Self) -> Ordering {
|
||||||
let a = self.0.as_ptr() as usize;
|
let a = a.0.as_ptr() as usize;
|
||||||
let b = rhs.0.as_ptr() as usize;
|
let b = b.0.as_ptr() as usize;
|
||||||
a.partial_cmp(&b)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Ord for VMExternRef {
|
|
||||||
#[inline]
|
|
||||||
fn cmp(&self, rhs: &Self) -> Ordering {
|
|
||||||
let a = self.0.as_ptr() as usize;
|
|
||||||
let b = rhs.0.as_ptr() as usize;
|
|
||||||
a.cmp(&b)
|
a.cmp(&b)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ impl ExternRef {
|
|||||||
/// This is *only* pointer equality, and does *not* run any inner value's
|
/// This is *only* pointer equality, and does *not* run any inner value's
|
||||||
/// `Eq` implementation.
|
/// `Eq` implementation.
|
||||||
pub fn ptr_eq(&self, other: &ExternRef) -> bool {
|
pub fn ptr_eq(&self, other: &ExternRef) -> bool {
|
||||||
self.inner == other.inner
|
VMExternRef::eq(&self.inner, &other.inner)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the host information for this `externref`, if previously created
|
/// Returns the host information for this `externref`, if previously created
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ use std::cmp;
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use std::hash::{Hash, Hasher};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::rc::{Rc, Weak};
|
use std::rc::{Rc, Weak};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
@@ -736,7 +737,26 @@ pub(crate) struct StoreInner {
|
|||||||
compiler: RefCell<Compiler>,
|
compiler: RefCell<Compiler>,
|
||||||
instances: RefCell<Vec<InstanceHandle>>,
|
instances: RefCell<Vec<InstanceHandle>>,
|
||||||
signal_handler: RefCell<Option<Box<SignalHandler<'static>>>>,
|
signal_handler: RefCell<Option<Box<SignalHandler<'static>>>>,
|
||||||
host_info: RefCell<HashMap<VMExternRef, Rc<RefCell<dyn Any>>>>,
|
host_info: RefCell<HashMap<HostInfoKey, Rc<RefCell<dyn Any>>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct HostInfoKey(VMExternRef);
|
||||||
|
|
||||||
|
impl PartialEq for HostInfoKey {
|
||||||
|
fn eq(&self, rhs: &Self) -> bool {
|
||||||
|
VMExternRef::eq(&self.0, &rhs.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for HostInfoKey {}
|
||||||
|
|
||||||
|
impl Hash for HostInfoKey {
|
||||||
|
fn hash<H>(&self, hasher: &mut H)
|
||||||
|
where
|
||||||
|
H: Hasher,
|
||||||
|
{
|
||||||
|
VMExternRef::hash(&self.0, hasher);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Store {
|
impl Store {
|
||||||
@@ -825,7 +845,7 @@ impl Store {
|
|||||||
"externref must be from this store"
|
"externref must be from this store"
|
||||||
);
|
);
|
||||||
let infos = self.inner.host_info.borrow();
|
let infos = self.inner.host_info.borrow();
|
||||||
infos.get(&externref.inner).cloned()
|
infos.get(&HostInfoKey(externref.inner.clone())).cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn set_host_info(
|
pub(crate) fn set_host_info(
|
||||||
@@ -839,9 +859,9 @@ impl Store {
|
|||||||
);
|
);
|
||||||
let mut infos = self.inner.host_info.borrow_mut();
|
let mut infos = self.inner.host_info.borrow_mut();
|
||||||
if let Some(info) = info {
|
if let Some(info) = info {
|
||||||
infos.insert(externref.inner.clone(), info)
|
infos.insert(HostInfoKey(externref.inner.clone()), info)
|
||||||
} else {
|
} else {
|
||||||
infos.remove(&externref.inner)
|
infos.remove(&HostInfoKey(externref.inner.clone()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user