actr_protocol/message.rs
1//! RpcRequest trait for type-safe RPC calls
2//!
3//! This module defines the `RpcRequest` trait which associates RPC Request types with their
4//! corresponding Response types. This enables compile-time type safety for client-side
5//! RPC calls through type inference.
6//!
7//! # Design Rationale
8//!
9//! Without the RpcRequest trait, client code must manually:
10//! 1. Encode the request into bytes
11//! 2. Specify the route_key as a string (prone to typos)
12//! 3. Manually decode the response (can use wrong type)
13//!
14//! With the RpcRequest trait, the framework can provide type-safe APIs:
15//! ```rust,ignore
16//! // Type-safe: compiler infers EchoResponse from EchoRequest::Response
17//! let response: EchoResponse = ctx.call(target, request).await?;
18//! ```
19//!
20//! # Implementation
21//!
22//! The RpcRequest trait is implemented by the code generator for each protobuf message
23//! that represents an RPC request:
24//!
25//! ```rust,ignore
26//! impl RpcRequest for EchoRequest {
27//! type Response = EchoResponse;
28//! }
29//! ```
30//!
31//! # Placement in actr-protocol
32//!
33//! This trait is placed in actr-protocol (not actr-framework) because:
34//! - It's a pure type-level association with no async methods
35//! - It only depends on prost::Message and standard traits
36//! - It can be independently tested without runtime dependencies
37//! - It follows the "data definition layer" principle of actr-protocol
38
39use prost::Message as ProstMessage;
40
41use crate::generated::actr::PayloadType;
42
43/// Associates an RPC Request type with its Response type for type-safe RPC calls.
44///
45/// This trait is only implemented for RPC request messages, not for:
46/// - RPC response messages (EchoResponse, etc.)
47/// - Streaming data (StreamChunk, MediaFrame)
48/// - Other protobuf messages
49///
50/// # Type Safety
51///
52/// The RpcRequest trait enables the framework to provide compile-time guarantees that:
53/// - The correct response type is used when decoding RPC responses
54/// - Type inference works seamlessly for `ctx.call<R: RpcRequest>(...)` APIs
55/// - Mismatched request/response pairs are caught at compile time
56///
57/// # Example
58///
59/// ```rust,ignore
60/// use actr_protocol::RpcRequest;
61/// use prost::Message as ProstMessage;
62///
63/// #[derive(Clone, PartialEq, ProstMessage)]
64/// pub struct EchoRequest {
65/// #[prost(string, tag = "1")]
66/// pub message: String,
67/// }
68///
69/// #[derive(Clone, PartialEq, ProstMessage)]
70/// pub struct EchoResponse {
71/// #[prost(string, tag = "1")]
72/// pub reply: String,
73/// }
74///
75/// // Generated by actr-cli codegen
76/// impl RpcRequest for EchoRequest {
77/// type Response = EchoResponse;
78/// }
79/// ```
80///
81/// # Usage in Client Code
82///
83/// ```rust,ignore
84/// use actr_framework::Context;
85///
86/// async fn call_echo_service<C: Context>(
87/// ctx: &C,
88/// target: &Dest,
89/// message: String
90/// ) -> ActorResult<String> {
91/// let request = EchoRequest { message };
92///
93/// // Type inference: compiler knows Response = EchoResponse
94/// let response = ctx.call(target, request).await?;
95///
96/// Ok(response.reply)
97/// }
98/// ```
99pub trait RpcRequest: ProstMessage + Default + Send + Sync + 'static {
100 /// The response type associated with this RPC request.
101 ///
102 /// This associated type enables compile-time type checking of request/response pairs.
103 /// When calling `ctx.call::<R>(...)`, the framework automatically decodes the
104 /// response bytes into `R::Response`.
105 type Response: ProstMessage + Default + Send + Sync + 'static;
106
107 /// Returns the route key for this RPC method.
108 ///
109 /// The route key identifies the specific RPC method to invoke, typically in the format
110 /// "package.Service.Method" (e.g., "echo.EchoService.Echo").
111 ///
112 /// This method is used by the framework to automatically populate the RpcEnvelope's
113 /// route_key field when making type-safe RPC calls.
114 fn route_key() -> &'static str;
115
116 /// Returns the PayloadType for this RPC method.
117 ///
118 /// The PayloadType determines the transmission characteristics (reliable vs. signal)
119 /// and is declared in the protobuf service definition:
120 ///
121 /// ```protobuf
122 /// rpc KickUser(KickRequest) returns (KickResponse) {
123 /// option (actr.payload_type) = RPC_SIGNAL;
124 /// }
125 /// ```
126 ///
127 /// If not specified, defaults to `PayloadType::RpcReliable`.
128 ///
129 /// This method is used by the framework to select the appropriate transmission lane
130 /// when making RPC calls.
131 fn payload_type() -> PayloadType {
132 PayloadType::RpcReliable
133 }
134}