Crate by_address [] [src]

Wrapper type for by-address hashing and comparison.

ByAddress can be used to wrap any pointer type (i.e. any type that implements the Deref trait). This includes references, raw pointers, smart pointers like Rc<T> and Box<T>, and specialized pointer-like types such as Vec<T> and String.

Comparison, ordering, and hashing of the wrapped pointer will be based on the address of its contents, rather than their value.

use by_address::ByAddress;
use std::rc::Rc;

let rc = Rc::new(5);
let x = ByAddress(rc.clone());
let y = ByAddress(rc.clone());

// x and y are two pointers to the same address:
assert_eq!(x, y);

let z = ByAddress(Rc::new(5));

// *x and *z have the same value, but not the same address:
assert_ne!(x, z);

You can use wrapped pointers as keys in hashed or ordered collections, like BTreeMap/BTreeSet or HashMap/HashSet, even if the target of the pointer doesn't implement hashing or ordering. This even includes pointers to trait objects, which usually don't implement the Eq trait because it is not object-safe.

/// Call each item in `callbacks`, skipping any duplicate references.
fn call_each_once(callbacks: &[&Fn()]) {
    let mut seen: HashSet<ByAddress<&Fn()>> = HashSet::new();
    for &f in callbacks {
        if seen.insert(ByAddress(f)) {
            f();
        }
    }
}

If T is a pointer to an unsized type, then comparison and ordering of ByAddress<T> compare the entire fat pointer, not just the "thin" data address. This means that two slice pointers are consider equal only if they have the same starting address and length.

let v = [1, 2, 3, 4];

assert_eq!(ByAddress(&v[0..4]), ByAddress(&v[0..4])); // Same address and length.
assert_ne!(ByAddress(&v[0..4]), ByAddress(&v[0..2])); // Same address, different length.

However, due to limitations of safe Rust, hashing takes only the data address into account. This may cause performance problems if you use slices as keys in a by-address HashMap or HashSet. It won't cause correctness bugs, but it may cause a high rate of hash collisions if the keys include many slices with the same starting points but different lengths.

fn hash<T: Hash>(t: T) -> u64 {
    let mut s = DefaultHasher::new();
    t.hash(&mut s);
    s.finish()
}

let v = [1, 2, 3, 4];
assert_eq!(hash(ByAddress(&v[0..4])),
           hash(ByAddress(&v[0..2]))); // Uh-oh!

This crate does not depend on libstd, so it can be used in no_std projects.

Structs

ByAddress

Wrapper for pointer types that implements by-address comparison.