Skip to main content

fizyr_rpc/
macros.rs

1//! Extra macro documentation.
2
3#[doc(hidden)]
4pub use fizyr_rpc_macros::interface as interface_impl;
5
6#[macro_export]
7/// Define an RPC interface.
8///
9/// This macro generates an `Interface, `Client` and `Server` struct, and some more helper types.
10///
11/// The `Interface` struct is used to enable RPC interface introspection.
12/// Currently, it only supports retrieving the documentation of the interface itself.
13/// In the future, you can use this struct to get a list of services and streaming messages too.
14///
15/// The client struct is used to initiate requests and send stream messages.
16/// It can be created from a [`PeerWriteHandle`] or a [`PeerHandle`].
17/// Note that if you create the client from a [`PeerHandle`], the [`PeerReadHandle`] will not be accessible.
18///
19/// For the server struct it is exactly the opposite: it is used to receive requests and stream messages.
20/// It can be created from a [`PeerReadHandle`] or a [`PeerHandle`],
21/// but creating it from a [`PeerHandle`] will discard the [`PeerWriteHandle`].
22///
23/// # Example
24///
25/// See the [`interface_example`] module for an example, with the source code and generated documentation.
26///
27/// # Syntax
28///
29/// The syntax for the macro is as follows:
30/// ```no_compile
31/// fizyr_rpc::interface! {
32///     // The `interface` keyword defines an RPC interface.
33///     // You must have exactly one interface definition in the macro invocation.
34///     //
35///     // The $interface_name is used in automatically generated documentation and should be UpperCamelCase.
36///     //
37///     // You can adjust the visiblity of the generated items with the `pub` keyword as normal.
38///     // By default, all generated items are private.
39///     //
40///     // Each item can have user written documentation.
41///     // Simply write doc comments with triple slashes as usual.
42///     // This applies to the interface definition, service definitions, update definitions and stream definitions.
43///     //
44///     // The documentation writter on the `interface` item can be retrieved through the introspection API,
45///     // but does not appear in rustdoc.
46///     pub interface $interface_name {
47///         // The `service` keyword defines a service.
48///         //
49///         // You can have any amount of service definitions inside an interface definition.
50///         //
51///         // The $id is used as the service ID and must be an i32.
52///         // The ID must be unique for all services in the interface.
53///         //
54///         // The $name is the name of the service.
55///         // It is used to generate function and type names.
56///         // It must be a valid Rust identifier and should be lowercase with underscores.
57///         //
58///         // The $request_type and $response_type indicate the message body for the request and the response.
59///         // If there is no data in a request or response, you can use the unit type: `()`
60///         //
61///         // If the service has no update messages, you can end the definition with a comma.
62///         // See the next item for the syntax of services with update messages.
63///         service $id $name: $request_type -> $response_type,
64///
65///         // If a service has update messages, you can declare them in the service block.
66///         service $id $name: $request_type -> $response_type {
67///             // The `request_update` keyword defines a request update.
68///             // You can have any amount of request updates inside a service definition.
69///             //
70///             // The $id is used as the service ID for the update and must be an i32.
71///             // The ID must be unique for all request updates in the service.
72///             //
73///             // The $name is the name of the update message.
74///             // It is used to generate function and type names.
75///             // It must be a valid Rust identifier and should be lowercase with underscores.
76///             //
77///             // The $body_type indicates the type of the message.
78///             // If there is no data in the message, you can use the unit type: `()`
79///             request_update $id $name: $body_type,
80///
81///             // The `response_update` keyword defines a response update.
82///             // You can have any amount of response updates inside a service definition.
83///             //
84///             // The $id is used as the service ID for the update and must be an i32.
85///             // The ID must be unique for all response updates in the service.
86///             //
87///             // The $name is the name of the update message.
88///             // It is used to generate function and type names.
89///             // It must be a valid Rust identifier and should be lowercase with underscores.
90///             //
91///             // The $body_type indicates the type of the message.
92///             // If there is no data in the message, you can use the unit type: `()`
93///             response_update $id $name: $body_type,
94///         }
95///
96///         // The `stream` keyword defines a stream message.
97///         // You can have any amount of stream definitions in an interface definition.
98///         //
99///         // The $id is used as the service ID of the stream message and must be an i32.
100///         // The ID must be unique for all streams in the interface.
101///         //
102///         // The $name is the name of the stream.
103///         // It is used to generate function and type names.
104///         // It must be a valid Rust identifier and should be lowercase with underscores.
105///         //
106///         // The $body_type indicates the type of the message.
107///         // If there is no data in the message, you can use the unit type: `()`
108///        stream $id $name: $body_type,
109///     }
110/// }
111/// ```
112///
113/// [`PeerHandle`]: crate::PeerHandle
114/// [`PeerWriteHandle`]: crate::PeerWriteHandle
115/// [`PeerReadHandle`]: crate::PeerReadHandle
116macro_rules! interface {
117	($($tokens:tt)*) => {
118		$crate::macros::interface_impl!{$crate; $($tokens)*}
119	}
120}
121
122/// Example module for the `interface!` macro.
123///
124/// You can compare the source of the generated documentation to inspect the generated API.
125/// The most important generated types are [`Client`] and [`Server`].
126///
127/// [`Client`]: interface_example::Client
128/// [`Server`]: interface_example::Server
129///
130/// ```no_compile
131/// fizyr_rpc::interface! {
132///     /// RPC interface for the supermarket.
133///     pub interface Supermarket {
134///         /// Greet the cashier.
135///         ///
136///         /// The cashier will reply with their own greeting.
137///         service 1 greet_cashier: String -> String,
138///
139///         /// Purchase tomatoes.
140///         ///
141///         /// The response of the cashier depends on the update messages exchanged.
142///         /// If you run away after they have sent the `price`, or if you pay with a nun-fungable token,
143///         /// they will respond with [`BuyTomatoesResponse::ICalledSecurity`].
144///         ///
145///         /// If you pay with the correct amount, they will respond with [`BuyTomatoesResponse::ThankYouComeAgain`].
146///         service 2 buy_tomatoes: BuyTomatoesRequest -> BuyTomatoesResponse {
147///             /// Sent once by the cashier to notify you of the price of the tomatoes.
148///             response_update 1 price: Price,
149///
150///             /// Sent by the client to pay for the tomatoes.
151///             request_update 1 pay: Payment,
152///
153///             /// Sent by broke or kleptomanic clients that still want tomatoes.
154///             request_update 2 run_away: (),
155///         }
156///
157///         /// Mutter something as you're walking through the supermarket.
158///         ///
159///         /// Since no-one will respond, this is a stream rather than a service.
160///         ///
161///         /// Popular phrases include:
162///         ///  * Woah thats cheap!
163///         ///  * Everything used to be better in the good old days...
164///         ///  * Why did they move the toilet paper?
165///         stream 1 mutter: String,
166///     }
167/// }
168///
169/// /// The initial request to buy tomatoes.
170/// #[derive(Debug)]
171/// pub struct BuyTomatoesRequest {
172///     /// The tomatoes you want to buy.
173///     pub amount: usize,
174/// }
175///
176/// /// The price for something.
177/// #[derive(Debug)]
178/// pub struct Price {
179///     /// The total price in cents.
180///     pub total_price_cents: usize,
181/// }
182///
183/// /// Payment options for purchasing tomatoes.
184/// #[derive(Debug)]
185/// pub enum Payment {
186///     /// Payment in money.
187///     Money {
188///         /// The amount of money in cents.
189///         cents: usize
190///     },
191///
192///     /// Payment with an NFT.
193///     NonFungibleToken,
194/// }
195///
196/// /// The response of a cashier when buying tomatoes.
197/// #[derive(Debug)]
198/// pub enum BuyTomatoesResponse {
199///     /// A final greeting and your receipt.
200///     ThankYouComeAgain(Receipt),
201///
202///     /// Security has been called.
203///     ICalledSecurity,
204/// }
205///
206/// /// A receipt for your purchase.
207/// #[derive(Debug)]
208/// pub struct Receipt {
209///     /// The number of tomatoes you bought.
210///     pub amount_of_tomatoes: usize,
211///
212///     /// The total price you paid for the tomatoes.
213///     pub total_price_cents: usize,
214///
215///     /// If the cashier really liked you, they may write their phone number on the receipt with pen.
216///     pub phone_number: Option<String>,
217/// }
218/// ```
219pub mod interface_example {
220	interface! {
221		/// RPC interface for the supermarket.
222		pub interface Supermarket {
223			/// Greet the cashier.
224			///
225			/// The cashier will reply with their own greeting.
226			service 1 greet_cashier: String -> String,
227
228			/// Purchase tomatoes.
229			///
230			/// The response of the cashier depends on the update messages exchanged.
231			/// If you run away after they have sent the `price`, or if you pay with a nun-fungable token,
232			/// they will respond with [`BuyTomatoesResponse::ICalledSecurity`].
233			///
234			/// If you pay with the correct amount, they will respond with [`BuyTomatoesResponse::ThankYouComeAgain`].
235			service 2 buy_tomatoes: BuyTomatoesRequest -> BuyTomatoesResponse {
236				/// Sent once by the cashier to notify you of the price of the tomatoes.
237				response_update 1 price: Price,
238
239				/// Sent by the client to pay for the tomatoes.
240				request_update 1 pay: Payment,
241
242				/// Sent by broke or kleptomanic clients that still want tomatoes.
243				request_update 2 run_away: (),
244			}
245
246			/// Mutter something as you're walking through the supermarket.
247			///
248			/// Since no-one will respond, this is a stream rather than a service.
249			///
250			/// Popular phrases include:
251			///  * Woah thats cheap!
252			///  * Everything used to be better in the good old days...
253			///  * Why did they move the toilet paper?
254			stream 1 mutter: String,
255		}
256	}
257
258	/// The initial request to buy tomatoes.
259	#[derive(Debug)]
260	pub struct BuyTomatoesRequest {
261		/// The tomatoes you want to buy.
262		pub amount: usize,
263	}
264
265	/// The price for something.
266	#[derive(Debug)]
267	pub struct Price {
268		/// The total price in cents.
269		pub total_price_cents: usize,
270	}
271
272	/// Payment options for purchasing tomatoes.
273	#[derive(Debug)]
274	pub enum Payment {
275		/// Payment in money.
276		Money {
277			/// The amount of money, in cents.
278			cents: usize,
279		},
280
281		/// Payment with an NFT.
282		NonFungibleToken,
283	}
284
285	/// The response of a cashier when buying tomatoes.
286	#[derive(Debug)]
287	pub enum BuyTomatoesResponse {
288		/// A final greeting and your receipt.
289		ThankYouComeAgain(Receipt),
290
291		/// Security has been called.
292		ICalledSecurity,
293	}
294
295	/// A receipt for your purchase.
296	#[derive(Debug)]
297	pub struct Receipt {
298		/// The number of tomatoes you bought.
299		pub amount_of_tomatoes: usize,
300
301		/// The total price you paid for the tomatoes.
302		pub total_price_cents: usize,
303
304		/// If the cashier really liked you, they may write their phone number on the receipt with pen.
305		pub phone_number: Option<String>,
306	}
307}