Misguided
Misguided

Reputation: 1302

How can I put a std::hash::Hasher within a Box?

I have a data structure that looks something like this:

pub struct X<K> {
    hasher: Box<std::hash::Hasher>,
    phantom: std::marker::PhantomData<K>,
}

And this is used as follows:

impl<K: std::hash::Hash> Trait<K> for X<K> {
    fn function(&mut self, key: &K) -> usize {
        ...
        key.hash(&mut *self.hasher);
        ...
    }
}

I am getting the following compiler error in the nightly:

The trait std::hash::Hasher is not implemented for std::boxed::Box<std::hash::Hasher + 'static>

Another approach is to use key.hash(self.hasher.deref_mut()), which triggers the following error:

std::hash::Hasher + 'static does not have a constant size known at compile-time

Both errors are in the hash call. I find it strange that std::hash::Hasher is not implemented for Box, but I wonder if this is not something done to protect me from myself. Aside from that, it seems weird that the deref_mut error complains about size known at compile time, considering that the Box should be a fixed size structure.

I know that a way to fix this would be to use a template parameter, but I am avoiding this since X will be used in other data structures which wouldn't need the parameter, and that would mean I would have to pass around an unnecessary parameter. It seems that this is the approach taken by HashMap, as it uses the RandomState template parameter, but I would prefer to avoid that if possible.

Upvotes: 2

Views: 334

Answers (1)

Shepmaster
Shepmaster

Reputation: 430673

I find it strange that std::hash::Hasher is not implemented for Box

I assume you mean for Box<T> where T: std::hash::Hasher. I don't know why it wouldn't be implemented, but it's probably just because no one has yet.

it seems weird that the deref_mut error complains about size known at compile time

The problem is that the generic type H has the implicit Sized bound (everything does by default):

fn hash<H>(&self, state: &mut H)
    where
        H: Hasher;

You'd need it to say:

fn hash<H>(&self, state: &mut H)
    where
        H: ?Sized + Hasher;

Again, I don't see any reason it couldn't be changed to do this, it's just most likely that no one needed it to.


You can add a newtype to work around the problem:

use std::hash;

pub struct X<K> {
    hasher: BoxedHasher,
    phantom: std::marker::PhantomData<K>,
}

struct BoxedHasher(Box<hash::Hasher>);

impl hash::Hasher for BoxedHasher {
    fn finish(&self) -> u64 {
        self.0.finish()
    }

    fn write(&mut self, bytes: &[u8]) {
        self.0.write(bytes)
    }
}

impl<K> X<K>
where
    K: hash::Hash,
{
    fn function(&mut self, key: &K) -> usize {
        key.hash(&mut self.hasher);
        0
    }
}

Upvotes: 2

Related Questions