use super::*;
use std::{hash::Hasher, ptr, rc::Rc};
pub struct HashRcByLoc<T>(pub Rc<T>);
impl<T> std::hash::Hash for HashRcByLoc<T> {
fn hash<H: Hasher>(&self, state: &mut H) {
let t = &self.0;
ptr::hash(&**t, state)
}
}
impl<T> PartialEq for HashRcByLoc<T> {
fn eq(&self, other: &Self) -> bool {
Rc::ptr_eq(&self.0, &other.0)
}
}
The point here is to do Eq/Hash by add of Rc rather than by contents of Rc.
One thing I don't like is that I often have to use ".0" to access the undelying Rc. What traits do I need to implement on HashRcByLoc to avoid the .0 ?
If you implement the Deref trait, for the most part, your &T can act like and be used in the place of &Target.
This is how Box acts is usable like the T it wraps, alongside the other "smart pointers" such as Arc and Rc.
Technically, you should probably have HashRcByLoc<T>: Deref<Target=T> rather than HashRcByLoc<T>: Deref<Target=Rc<T>>, due to the specific semantics of Deref, but any place one type should be used as-if it were another type is a reasonable enough place to impl Deref.
Also consider using shrinkwraprs to automate some of the newtype-forwarding boilerplate.
You might be interested in my by_address crate. ByAddress<Rc<T>> implements Eq, PartialEq, Hash, Ord, and PartialOrd by address comparison. You can also use it with other shared pointer types, like ByAddress<Arc<T>> or ByAddress<&T>.