I have a messaging system and want to solve everything generically. Messages can be sent to entities and the entities can handle the messages.
// There are many messages that implement this trait
trait Message {
type Response;
}
// Messages can be sent to 'entities'
trait Entity {
type Error;
}
// Entities can implement handlers for specific messages
trait MessageHandler<M: Message>: Entity {
fn handle(
&mut self,
message: M,
) -> Result<M::Response, Self::Error>;
}
This would be implemented like so:
struct SimpleEntity;
impl Entity for SimpleEntity {
type Error = ();
}
struct SimpleMessage;
impl Message for SimpleMessage {
type Response = ();
}
impl MessageHandler<SimpleMessage> for SimpleEntity {
fn handle(
&mut self,
message: SimpleMessage,
) -> Result<(), ()> {
Ok(())
}
}
All entities are stored in a system. The system can only store entities of 1 type. For every message handler that the type has, there should be a send_message
function that takes the message generically.
I imagine it could look like this:
// A message system for one type of entity. This is an example. Normally there's all kinds of async multithreaded stuff here
struct MessageSystem<E: Entity> {
handlers: Vec<E>,
}
// For every message handler, we want to implement the send_message function
impl<M: Message, MH: MessageHandler<M>> MessageSystem<MH> {
pub fn send_message(&mut self, entity_id: (), message: M) -> Result<M::Response, MH::Error> {
unimplemented!();
}
}
This could then be used like so:
// Example usage
fn main() {
let mut system = MessageSystem { handlers: vec![SimpleEntity] };
system.send_message((), SimpleMessage).unwrap();
}
However, this gives a compile error in the impl block for the send_message
function:
error[E0207]: the type parameter `M` is not constrained by the impl trait, self type, or predicates
--> src/lib.rs:25:6
|
25 | impl<M: Message, MH: MessageHandler<M>> MessageSystem<MH> {
| ^ unconstrained type parameter
error: aborting due to previous error
For more information about this error, try `rustc --explain E0207`.
How could I make this work?
The goal is to have these different message structs, have them be handled by a handler that an entity can implement and send the messages to the entities via the system struct.
An obvious thing would be to make the message an associated type in the MessageHandler
trait, but then you can't implement multiple versions of it for an entity.