Search code examples
rusttrait-objects

Trait can't be made Object Safe when Hash + PartialEq are Supertraits


I'm pretty new to Rust, so there is the possibility that this will be an easy Question.

I'm trying to create a small registry for Handlers that should return any struct that implements the TransferObject Trait:

pub trait TransferObject: Hash + PartialEq {}

Since I store the Handlers that are registered in a HashMap the Trait needs the Hash and PartialEq as the Supertraits:

pub struct RequestHandlerRegistry {
    handlers: HashMap<RequestMethod, HashMap<String, RequestHandler<dyn TransferObject>>>,
}

But in the Struct I get the Error, that TransferObject can't be made into an Object since PartialEq uses the parameter Self. I already tried to do something like this:

pub struct RequestHandlerRegistry {
    handlers: HashMap<RequestMethod, HashMap<String, RequestHandler<Box<dyn TransferObject>>>>,
}

But I still get the same Error.
Is there some way to get around this?
I also created a Playground for easy recreation of the Error.


Solution

  • This doesn't work because PartialEq by default means PartialEq<Self>. When using dynamic dispatch (dyn) there isn't enough information to know what Self is and therefore what type of reference the methods of PartialEq can accept.

    However, your question belies a misunderstanding that got you into this mess:

    Since I store the Handlers that are registered in a HashMap the Trait needs the Hash and PartialEq as the Supertraits

    This is only true for things you use as keys. There are no such restrictions on values.

    You can therefore drop the supertraits Hash and PartialEq from this trait; instead you need to add Hash, PartialEq, and Eq to the #[derive] macro for RequestMethod, since that's what you're using as a key.

    Finally, you will indeed need Box to hold the dyn TransferObject values to give them a known size.