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}