Is there a way to Hash a Weak<T>?

Based on &* on a Weak<T>, Weak, RC, Drop, Free - #9 by Yandros , getting the address of the RcBox and using it as a usize would suffice.

Based on Address of a Weak<T> - #4 by alice , we can't get the address of the RcBox, but we can try to get the address of the T inside of it.

However, based on Weak<T>.as_raw() - #2 by CAD97 , it seems that the as_ptr is not stable.

===

Why do you need to Hash Weak<T> ?

I want to use it as a key to a HashMap.

Can you use a Rc<T> instead ?

No, for various gc/loop reasons, I need it to be Weak

You can upgrade it to an Rc, use into_raw to obtain a pointer, then use from_raw to avoid leaking the Rc. You can then cache this pointer next to your Weak.

1 Like

@alice: Are you suggesting:

pub struct CanHashWeak<T> {
  ptr: *const T,
  weak: Weak<T>,
}

and do a custom Eq/Hash on CanHashWeak ?

EDIT: where the key is a CanHashWeak<T> instead of a Weak<T>

Yes exactly. You can convert the pointer to an usize if you prefer.

1 Like

The good thing about

use ::std::{
    hash::{Hash, Hasher},
    rc::{self, Rc},
};

pub
struct CanHashWeak<T> {
  ptr: *const T,
  weak: rc::Weak<T>,
}

impl<T> CanHashWeak<T> {
    // pub /* if you want */
    fn ptr (self: &'_ Self) -> *const T
    {
        self.ptr
    }
}

impl<T> Hash for CanHashWeak<T> {
    fn hash<H : Hasher> (self: &'_ Self, hasher: &'_ mut H)
    {
        self.ptr().hash(hasher)
    }
}

impl<T> Eq for CanHashWeak<T> {}
impl<T> PartialEq for CanHashWeak<T> {
    fn eq (self: &'_ Self, other: &'_ Self) -> bool
    {
        self.ptr() == other.ptr()
    }
}

is that the redundancy of having the pointer twice (since a Weak<T> is currently implemented as a *const T pointer but with an offset), can be transparently removed in the implementation without affecting the API, once rc::Weak::as_raw gets stabilized:

impl<T> CanHashWeak<T> {
    // pub /* if you want */
    fn ptr (self: &'_ Self) -> *const T
    {
        self.weak.as_raw()
    }
}
4 Likes

Note that if you impl Hash on some type T, any operation works with &T must not change its hash value. The std::collection::HashMap's api is built on this assumption. This is why the RefCell<T> doesn't impl Hash. Approach using Weak::upgrade() is not valid for this reason

.

2 Likes

Maybe you look for the weak-table crate?

The CanHashWeak type proposed here will never have its hash value changed due to caching the pointer.

1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.