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}