actr-protocol 0.2.1

Unified protocol, types, and URI parsing for Actor-RTC framework
Documentation
//! RpcRequest trait for type-safe RPC calls
//!
//! This module defines the `RpcRequest` trait which associates RPC Request types with their
//! corresponding Response types. This enables compile-time type safety for caller-side
//! RPC calls through type inference.
//!
//! # Design Rationale
//!
//! Without the RpcRequest trait, client code must manually:
//! 1. Encode the request into bytes
//! 2. Specify the route_key as a string (prone to typos)
//! 3. Manually decode the response (can use wrong type)
//!
//! With the RpcRequest trait, the framework can provide type-safe APIs:
//! ```rust,ignore
//! // Type-safe: compiler infers EchoResponse from EchoRequest::Response
//! let response: EchoResponse = ctx.call(target, request).await?;
//! ```
//!
//! # Implementation
//!
//! The RpcRequest trait is implemented by the code generator for each protobuf message
//! that represents an RPC request:
//!
//! ```rust,ignore
//! impl RpcRequest for EchoRequest {
//!     type Response = EchoResponse;
//! }
//! ```
//!
//! # Placement in actr-protocol
//!
//! This trait is placed in actr-protocol (not actr-framework) because:
//! - It's a pure type-level association with no async methods
//! - It only depends on prost::Message and standard traits
//! - It can be independently tested without runtime dependencies
//! - It follows the "data definition layer" principle of actr-protocol

use prost::Message as ProstMessage;

use crate::generated::actr::PayloadType;

/// Associates an RPC Request type with its Response type for type-safe RPC calls.
///
/// This trait is only implemented for RPC request messages, not for:
/// - RPC response messages (EchoResponse, etc.)
/// - Streaming data (StreamChunk, MediaFrame)
/// - Other protobuf messages
///
/// # Type Safety
///
/// The RpcRequest trait enables the framework to provide compile-time guarantees that:
/// - The correct response type is used when decoding RPC responses
/// - Type inference works seamlessly for `ctx.call<R: RpcRequest>(...)` APIs
/// - Mismatched request/response pairs are caught at compile time
///
/// # Example
///
/// ```rust,ignore
/// use actr_protocol::RpcRequest;
/// use prost::Message as ProstMessage;
///
/// #[derive(Clone, PartialEq, ProstMessage)]
/// pub struct EchoRequest {
///     #[prost(string, tag = "1")]
///     pub message: String,
/// }
///
/// #[derive(Clone, PartialEq, ProstMessage)]
/// pub struct EchoResponse {
///     #[prost(string, tag = "1")]
///     pub reply: String,
/// }
///
/// // Generated by actr-cli codegen
/// impl RpcRequest for EchoRequest {
///     type Response = EchoResponse;
/// }
/// ```
///
/// # Usage in Client Code
///
/// ```rust,ignore
/// use actr_framework::Context;
///
/// async fn call_echo_service<C: Context>(
///     ctx: &C,
///     target: &Dest,
///     message: String
/// ) -> ActorResult<String> {
///     let request = EchoRequest { message };
///
///     // Type inference: compiler knows Response = EchoResponse
///     let response = ctx.call(target, request).await?;
///
///     Ok(response.reply)
/// }
/// ```
pub trait RpcRequest: ProstMessage + Default + Send + Sync + 'static {
    /// The response type associated with this RPC request.
    ///
    /// This associated type enables compile-time type checking of request/response pairs.
    /// When calling `ctx.call::<R>(...)`, the framework automatically decodes the
    /// response bytes into `R::Response`.
    type Response: ProstMessage + Default + Send + Sync + 'static;

    /// Returns the route key for this RPC method.
    ///
    /// The route key identifies the specific RPC method to invoke, typically in the format
    /// "package.Service.Method" (e.g., "echo.EchoService.Echo").
    ///
    /// This method is used by the framework to automatically populate the RpcEnvelope's
    /// route_key field when making type-safe RPC calls.
    fn route_key() -> &'static str;

    /// Returns the PayloadType for this RPC method.
    ///
    /// The PayloadType determines the transmission characteristics (reliable vs. signal)
    /// and is declared in the protobuf service definition:
    ///
    /// ```protobuf
    /// rpc KickUser(KickRequest) returns (KickResponse) {
    ///     option (actr.payload_type) = RPC_SIGNAL;
    /// }
    /// ```
    ///
    /// If not specified, defaults to `PayloadType::RpcReliable`.
    ///
    /// This method is used by the framework to select the appropriate transmission lane
    /// when making RPC calls.
    fn payload_type() -> PayloadType {
        PayloadType::RpcReliable
    }
}