Macro impl_message_handler

Source
macro_rules! impl_message_handler {
    ([$($generics:tt)*] for $actor_type:ty, [$($msg_type:ty),* $(,)?]) => { ... };
    ($actor_type:ty, [$($msg_type:ty),* $(,)?]) => { ... };
}
Expand description

Implements the MessageHandler trait for both generic and non-generic actor types.

This macro simplifies the process of handling multiple message types within an actor. It generates the necessary boilerplate code to downcast a Box<dyn Any + Send> message to its concrete type and then calls the appropriate Message::handle implementation on the actor.

§Usage

§For non-generic actors:

struct MyActor;

impl Actor for MyActor { /* ... */ }

struct Msg1;
struct Msg2;

impl Message<Msg1> for MyActor {
    type Reply = ();
    async fn handle(&mut self, msg: Msg1, _actor_ref: &ActorRef<Self>) -> Self::Reply { /* ... */ }
}

impl Message<Msg2> for MyActor {
    type Reply = String;
    async fn handle(&mut self, msg: Msg2, _actor_ref: &ActorRef<Self>) -> Self::Reply {
        /* ... */ "response".to_string()
    }
}

// This will implement `MessageHandler` for `MyActor`, allowing it to handle `Msg1` and `Msg2`.
impl_message_handler!(MyActor, [Msg1, Msg2]);

§For generic actors:

struct GenericActor<T: Send + Debug + Clone + 'static> {
    data: Option<T>,
}

impl<T: Send + Debug + Clone + 'static> Actor for GenericActor<T> { /* ... */ }

struct SetValue<T: Send + Debug + 'static>(T);
struct GetValue;

impl<T: Send + Debug + Clone + 'static> Message<SetValue<T>> for GenericActor<T> {
    type Reply = ();
    async fn handle(&mut self, msg: SetValue<T>, _actor_ref: &ActorRef<Self>) -> Self::Reply { /* ... */ }
}

impl<T: Send + Debug + Clone + 'static> Message<GetValue> for GenericActor<T> {
    type Reply = Option<T>;
    async fn handle(&mut self, msg: GetValue, _actor_ref: &ActorRef<Self>) -> Self::Reply { /* ... */ }
}

// This will implement `MessageHandler` for the generic `GenericActor<T>`.
impl_message_handler!([T: Send + Debug + Clone + 'static] for GenericActor<T>, [SetValue<T>, GetValue]);

§Arguments

§Non-generic form:

  • $actor_type:ty: The type of the actor for which to implement MessageHandler.
  • [$($msg_type:ty),* $(,)?]: A list of message types that the actor can handle.
impl_message_handler!(MyActor, [Msg1, Msg2]);

§Generic form:

  • [$($generics:tt)*]: Generic type parameters with their trait bounds (as token tree to handle complex bounds)
  • for $actor_type:ty: The generic actor type for which to implement MessageHandler
  • [$($msg_type:ty),* $(,)?]: A list of message types that the actor can handle
impl_message_handler!([T: Send + Debug + Clone + 'static] for GenericActor<T>, [SetValue<T>, GetValue]);

§Internals

This macro facilitates dynamic message dispatch by downcasting Box<dyn std::any::Any + Send> message payloads to their concrete types at runtime. It implements the MessageHandler trait for your actor, enabling it to handle multiple message types through the handle method. The actual message handling logic is generated by the internal __impl_message_handler_body! helper macro to avoid code duplication between different implementation patterns.