Skip to main content

Message

Trait Message 

Source
pub trait Message<T: Send + 'static>: Actor {
    type Reply: Send + 'static;

    // Required method
    fn handle(
        &mut self,
        msg: T,
        actor_ref: &ActorRef<Self>,
    ) -> impl Future<Output = Self::Reply> + Send;

    // Provided method
    fn on_tell_result(_result: &Self::Reply, _actor_ref: &ActorRef<Self>) { ... }
}
Expand description

A trait for messages that an actor can handle, defining the reply type.

An actor struct implements this trait for each specific message type it can process. Messages are sent to actors using methods like tell, ask, or their variants.

Required Associated Types§

Source

type Reply: Send + 'static

The type of the reply that will be sent back to the caller.

Required Methods§

Source

fn handle( &mut self, msg: T, actor_ref: &ActorRef<Self>, ) -> impl Future<Output = Self::Reply> + Send

Handles the incoming message and produces a reply.

The actor_ref parameter is a reference to the actor’s own ActorRef. This is an asynchronous method where the actor’s business logic for processing the message T resides.

This method is called by the actor system when a message is received via tell, ask, or their variants.

Provided Methods§

Source

fn on_tell_result(_result: &Self::Reply, _actor_ref: &ActorRef<Self>)

Called after a tell() message handler completes.

This hook allows inspecting the handler’s return value for fire-and-forget messages. For ask() calls, this method is NOT invoked — the caller receives the result directly.

§Design decisions

This hook is designed as a synchronous, stateless logging hook:

  • No &self: The actor’s mutable state is not accessible. This prevents side effects and keeps the hook purely observational.
  • Not async: Asynchronous operations (e.g., sending messages to other actors) are intentionally excluded to avoid hidden control flow in fire-and-forget paths.
  • These constraints may be relaxed in future versions if use cases arise.

The default implementation does nothing. When using the #[handler] macro with a Result<T, E> return type (where E: Display), an override is automatically generated that logs errors via tracing::error!.

§Display bound enforcement

The generated tracing::error!("...: {}", e) implicitly requires E: Display. Since E is embedded inside Self::Reply = Result<T, E>, a where E: Display clause cannot be added directly on a trait method override. In the #[handler(result)] + type alias case, the proc macro cannot know the concrete E type at all, making an explicit bound fundamentally impossible.

Therefore, implicit enforcement via the {} format specifier is adopted. If E does not implement Display, the compiler emits `MyError` doesn't implement `std::fmt::Display` which is clear enough for the user to diagnose immediately.

§Automatic generation

The #[handler] macro generates an override when:

  • The return type is syntactically Result<T, E> (auto-detected)
  • The attribute #[handler(result)] is explicitly specified

Use #[handler(no_log)] to suppress automatic generation.

§Manual override

For manual Message trait implementations, override this method directly:

fn on_tell_result(result: &Self::Reply, actor_ref: &ActorRef<Self>) {
    if let Err(ref e) = result {
        tracing::error!(actor = %actor_ref.identity(), "error: {}", e);
    }
}

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.

Implementors§