Skip to main content

actr_framework/
dispatcher.rs

1//! MessageDispatcher trait - Message routing and dispatching
2
3use actr_protocol::{ActorResult, RpcEnvelope};
4use async_trait::async_trait;
5use bytes::Bytes;
6
7use crate::{Context, Workload};
8
9/// MessageDispatcher - Message dispatcher interface
10///
11/// Responsible for routing incoming message envelopes to corresponding handler methods.
12///
13/// # Design Characteristics
14///
15/// - **Static routing**: Implemented via compile-time match statements, no runtime lookup overhead
16/// - **Zero-sized type (ZST)**: Router itself occupies no memory
17/// - **Code generation**: Implementation is auto-generated by `actr-cli` codegen
18///
19/// # Code Generation Example
20///
21/// ```rust,ignore
22/// // Generated by code generator
23/// pub struct EchoServiceRouter<T: EchoServiceHandler>(PhantomData<T>);
24///
25/// #[async_trait]
26/// impl<T: EchoServiceHandler> MessageDispatcher for EchoServiceRouter<T> {
27///     type Workload = EchoServiceWorkload<T>;
28///
29///     async fn dispatch<C: Context>(
30///         workload: &Self::Workload,
31///         envelope: RpcEnvelope,
32///         ctx: &C,
33///     ) -> ActorResult<Bytes> {
34///         match envelope.route_key.as_str() {
35///             "echo.EchoService.Echo" => {
36///                 let req = EchoRequest::decode(&*envelope.payload)?;
37///                 let resp = workload.0.echo(req, ctx).await?;
38///                 Ok(resp.encode_to_vec().into())
39///             }
40///             _ => Err(ProtocolError::Actr(ActrError::UnknownRoute {
41///                 route_key: envelope.route_key.to_string()
42///             }))
43///         }
44///     }
45/// }
46/// ```
47// Same cross-target rationale as `Context` / `Workload`: `?Send` on wasm32,
48// native default `Send` auto trait elsewhere. `MaybeSendSync` silently
49// re-adds `Send + Sync` on native.
50#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
51#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
52pub trait MessageDispatcher: crate::MaybeSendSync + 'static {
53    /// Associated Workload type
54    type Workload: Workload<Dispatcher = Self>;
55
56    /// Dispatch message to corresponding handler method and execute full request-response cycle
57    ///
58    /// # Responsibilities
59    ///
60    /// 1. **Routing**: Select handler method based on `envelope.route_key`
61    /// 2. **Decoding**: Deserialize payload into concrete message type
62    /// 3. **Dispatching**: Invoke workload's business logic method
63    /// 4. **Encoding**: Serialize response into bytes
64    ///
65    /// # Parameters
66    ///
67    /// - `workload`: Workload instance (contains user business logic)
68    /// - `envelope`: Message envelope (contains route_key and payload)
69    /// - `ctx`: Execution context (generic, supports any Context implementation)
70    ///
71    /// # Returns
72    ///
73    /// Returns serialized response bytes
74    async fn dispatch<C: Context>(
75        workload: &Self::Workload,
76        envelope: RpcEnvelope,
77        ctx: &C,
78    ) -> ActorResult<Bytes>;
79}