Skip to main content

razor_rpc_macros/
lib.rs

1extern crate proc_macro;
2use proc_macro::TokenStream;
3
4mod endpoint_async;
5mod endpoint_client;
6mod service;
7mod service_mux_struct;
8
9/// The `#[service]` macro is applied to an `impl Trait for Struct` block to automatically
10/// generate the `ServiceStatic` implementation for the type.
11///
12/// - When applied to a trait `impl` block, all methods defined in the trait will be registered as service methods.
13/// - All service methods must return `Result<T, RpcError<E>>`, where `E` is a user-defined error type that implements `RpcErrCodec`.
14///
15/// The service method recognizes:
16/// - `async fn`
17/// - `impl Future`
18/// - trait methods wrapped by `async_trait`
19///
20/// # Usage
21///
22/// Define a service trait and implement it for your service struct:
23///
24/// ```rust
25/// use razor_rpc::server::service;
26/// use razor_rpc::error::RpcError;
27/// use serde::{Deserialize, Serialize};
28/// use std::future::Future;
29///
30/// #[derive(Debug, Deserialize, Serialize)]
31/// pub struct EchoArgs {
32///     message: String,
33/// }
34///
35/// #[derive(Debug, Deserialize, Serialize)]
36/// pub struct EchoResp {
37///     echoed: String,
38/// }
39///
40/// pub trait EchoService: Send + Sync {
41///     fn echo(&self, args: EchoArgs) -> impl Future<Output = Result<EchoResp, RpcError<()>>> + Send;
42/// }
43///
44/// pub struct EchoServiceImpl;
45///
46/// #[service]
47/// impl EchoService for EchoServiceImpl {
48///     fn echo(&self, args: EchoArgs) -> impl Future<Output = Result<EchoResp, RpcError<()>>> + Send {
49///         async move {
50///             Ok(EchoResp { echoed: args.message })
51///         }
52///     }
53/// }
54/// ```
55#[proc_macro_attribute]
56pub fn service(_attr: TokenStream, item: TokenStream) -> TokenStream {
57    service::service(_attr, item)
58}
59
60/// The `#[service_mux_struct]` macro is applied to a **struct** to implement `ServiceTrait` on it.
61/// It acts as a dispatcher, routing `serve()` calls to the correct service based on the `req.service` field.
62///
63/// Each field in the struct must hold a service that implements `ServiceTrait` (e.g., wrapped in an `Arc`).
64/// The macro generates a `serve` implementation that matches `req.service` against the field names of the struct.
65///
66/// # Usage
67///
68/// ```rust
69/// use razor_rpc::server::{service, service_mux_struct};
70/// use razor_rpc::error::RpcError;
71/// use serde::{Deserialize, Serialize};
72/// use std::sync::Arc;
73///
74/// // Define request/response types
75/// #[derive(Debug, Deserialize, Serialize)]
76/// pub struct MathArgs {
77///     value: i32,
78/// }
79///
80/// #[derive(Debug, Deserialize, Serialize)]
81/// pub struct MathResp {
82///     result: i32,
83/// }
84///
85/// // Define service trait
86/// pub trait MathService {
87///     async fn add(&self, args: MathArgs) -> Result<MathResp, RpcError<()>>;
88///     async fn multiply(&self, args: MathArgs) -> Result<MathResp, RpcError<()>>;
89/// }
90///
91/// // Define services
92/// pub struct AddService;
93/// #[service]
94/// impl MathService for AddService {
95///     async fn add(&self, args: MathArgs) -> Result<MathResp, RpcError<()>> {
96///         Ok(MathResp { result: args.value + 1 })
97///     }
98///     async fn multiply(&self, _args: MathArgs) -> Result<MathResp, RpcError<()>> {
99///         unimplemented!()
100///     }
101/// }
102///
103/// pub struct MultiplyService;
104/// #[service]
105/// impl MathService for MultiplyService {
106///     async fn add(&self, _args: MathArgs) -> Result<MathResp, RpcError<()>> {
107///         unimplemented!()
108///     }
109///     async fn multiply(&self, args: MathArgs) -> Result<MathResp, RpcError<()>> {
110///         Ok(MathResp { result: args.value * 2 })
111///     }
112/// }
113///
114/// // Create a service multiplexer
115/// #[service_mux_struct]
116/// pub struct ServiceMux {
117///     pub add: Arc<AddService>,
118///     pub multiply: Arc<MultiplyService>,
119/// }
120///
121/// // Usage:
122/// // let mux = ServiceMux {
123/// //     add: Arc::new(AddService),
124/// //     multiply: Arc::new(MultiplyService),
125/// // };
126/// ```
127#[proc_macro_attribute]
128pub fn service_mux_struct(_attr: TokenStream, item: TokenStream) -> TokenStream {
129    service_mux_struct::service_mux_struct(_attr, item)
130}
131
132/// The `endpoint_client!` macro generates a client struct that can be used to make remote API calls.
133///
134/// This macro should be used first to define the client struct, then use `#[endpoint_async]`
135/// to implement service traits for the client.
136///
137/// # Usage
138///
139/// ```rust
140/// use razor_rpc::client::endpoint_client;
141///
142/// endpoint_client!(MyClient);
143///
144/// // This generates MyClient<C> struct with:
145/// // - new(caller: C) constructor
146/// // - Clone implementation
147/// // - AsyncEndpoint<C> implementation
148/// ```
149#[proc_macro]
150pub fn endpoint_client(input: TokenStream) -> TokenStream {
151    endpoint_client::endpoint_client(input)
152}
153
154/// The `#[endpoint_async]` macro applies to a trait to implement it for a client struct.
155///
156/// The client struct must be defined beforehand using `#[endpoint_client(ClientName)]`.
157///
158/// Rules:
159///     - trait can be wrapped async_trait, optionally.
160///     - If trait is not async_trait, then the method should use the signature `impl Future + Send`
161///     - No fn is allowed.
162///     - All method should have one and only argument, and return type should be `Result<Resp, RpcError<E>>`, where `E: RpcErrCodec`
163///
164/// # Usage
165///
166/// ```rust
167/// use razor_rpc::client::{endpoint_client, endpoint_async};
168/// use razor_rpc::error::RpcError;
169/// use serde::{Deserialize, Serialize};
170/// use std::future::Future;
171///
172/// #[derive(Debug, Deserialize, Serialize)]
173/// pub struct AddArgs {
174///     pub a: i32,
175///     pub b: i32,
176/// }
177///
178/// #[derive(Debug, Deserialize, Serialize, Default)]
179/// pub struct AddResp {
180///     pub result: i32,
181/// }
182///
183/// // Step 1: Define the client struct
184/// endpoint_client!(CalculatorClient);
185///
186/// // Step 2: Define a service trait and implement it for the client
187/// #[endpoint_async(CalculatorClient)]
188/// pub trait CalculatorService {
189///     fn add(&self, args: AddArgs) -> impl Future<Output = Result<AddResp, RpcError<()>>> + Send;
190/// }
191///
192/// // Usage:
193/// // let client = CalculatorClient::new(caller);
194/// // let result = client.add(AddArgs { a: 1, b: 2 }).await;
195/// ```
196///
197/// The macro also supports `async fn` methods when used with `#[async_trait]`.
198#[proc_macro_attribute]
199pub fn endpoint_async(attr: TokenStream, item: TokenStream) -> TokenStream {
200    endpoint_async::endpoint_async(attr, item)
201}