How to use [u8; >32] as map key


#1

Hello!

I’m very new to Rust, so forgive me it’s something simple (probably is).

I’m trying to use a HashMap (with a custom hasher) with a key type [u8; 40]. The compiler obviously tells me, that I could only use up to length 32, above that I would have to implement a lot of Traits.

How could I actually do this?

Thanks!


#2

In current version of Rust arrays are very limited. It’s going to be fixed eventually when const generics are aded.

You can pass a slice to a custom hasher. Instead of foo: [u8; 40] pass &foo, which will be a variable-length slice of &[u8], and it supports hash for any length.

For automatically derived traits use newtype instead of the raw array:

pub struct MyKey([u8; 40]);

impl Hash for MyKey {…a chunk of code goes here. you can reuse hash of slices…}

or

#[derive(Hash)]
pub struct MyKey([u8; 20], [u8; 20]);

:smiley:


#3

You can also consider:

#[derive(Hash)]
struct Key([[u8; 20]; 2]);

And then use a bit of unsafe to reinterpret as [u8; 40] when needed. That should be sound given array layout guarantees.


#4

Thanks!

So just to be clear (it compiles, I’m just not sure it does what I think it does), this code should be fine for my needs? (I’m using MetroHashMap btw)

pub struct Key([u8; 40]);

impl Hash for Key {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.0.hash(state);
    }
}

impl PartialEq for Key {
    fn eq(&self, other: &Key) -> bool {
        self.0[..] == other.0[..]
    }
}

impl Eq for Key {}

#5

Yeah, that should work - self.0.hash(state) is using the blanket slice impl, if that’s what you were wondering about.