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}