tonic_rpc/
lib.rs

1//! `tonic-rpc` is a macro that generates the traits and stubs used by [`tonic`](https://crates.io/crates/tonic)
2//! from Rust definitions instead of `proto` files.
3//!
4//! This means that you can get all the [benefits](https://github.com/hyperium/tonic#features)
5//! of `tonic` while using regular Rust types and without needing to use `proto` files or build scripts.
6//! Of course, this comes at the sacrifice of interoperability.
7//!
8//! # Alternatives
9//! [`tarpc`](https://crates.io/crates/tarpc) is an excellent RPC library that also defines services
10//! as a Rust trait.
11//!
12//! # Required dependencies
13//! ```toml
14//! tonic = "0.8"
15//! tonic-rpc = { version = "0.2", features = [ <enabled-codecs> ] }
16//! ```
17//!
18//! # Example
19//! Instead of defining a `proto` file, define a service as a trait:
20//! ```no_run
21//! # #[cfg(feature = "json")]
22//! #[tonic_rpc::tonic_rpc(json)]
23//! trait Increment {
24//!     fn increment(arg: i32) -> i32;
25//! }
26//! # fn main() {}
27//! ```
28//! The attribute **`#[tonic_rpc(json)]`** indicates that this service
29//! will serialize the requests and responses using `json`.
30//! Other [`encodings are available`](#encodings).
31//! The arguments and return values for each function must implement
32//! `serde::Serialize` and `serde::Deserialize`.
33//!
34//! The service can be implemented by defining an `impl`:
35//! ```no_run
36//! # #[cfg(feature = "json")]
37//! # #[tonic_rpc::tonic_rpc(json)]
38//! # trait Increment {
39//! #     fn increment(arg: i32) -> i32;
40//! # }
41//! struct State;
42//!
43//! # #[cfg(feature = "json")]
44//! #[tonic::async_trait]
45//! impl increment_server::Increment for State {
46//!     async fn increment(
47//!         &self,
48//!         request: tonic::Request<i32>,
49//!     ) -> Result<tonic::Response<i32>, tonic::Status> {
50//!         Ok(tonic::Response::new(request.into_inner() + 1))
51//!     }
52//! }
53//! # fn main() {}
54//! ```
55//!
56//! And a server and client can be run:
57//! ```rust
58//! # #[cfg(feature = "json")]
59//! # #[tonic_rpc::tonic_rpc(json)]
60//! # trait Increment {
61//! #     fn increment(arg: i32) -> i32;
62//! # }
63//! # struct State;
64//! #
65//! # #[cfg(feature = "json")]
66//! # #[tonic::async_trait]
67//! # impl increment_server::Increment for State {
68//! #     async fn increment(
69//! #         &self,
70//! #         request: tonic::Request<i32>,
71//! #     ) -> Result<tonic::Response<i32>, tonic::Status> {
72//! #       Ok(tonic::Response::new(request.into_inner() + 1))
73//! #   }
74//! # }
75//! # #[cfg(feature = "json")]
76//! async fn run_client_server() {
77//!     let mut listener = tokio::net::TcpListener::bind("[::1]:0").await.unwrap();
78//!     let addr = listener.local_addr().unwrap();
79//!     tokio::spawn(async move {
80//!         tonic::transport::Server::builder()
81//!             .add_service(increment_server::IncrementServer::new(State))
82//!             .serve_with_incoming(tokio_stream::wrappers::TcpListenerStream::new(listener))
83//!             .await
84//!     });
85//!     let mut client = increment_client::IncrementClient::connect(format!("http://{}", addr))
86//!         .await
87//!         .unwrap();
88//!     let response = client.increment(32).await.unwrap().into_inner();
89//!     assert_eq!(33, response);
90//! }
91//! # #[cfg(feature = "json")]
92//! # fn main() {
93//! #     run_client_server();
94//! # }
95//! # #[cfg(not(feature = "json"))]
96//! # fn main() {}
97//! ```
98//!
99//! The full example is available [here](https://github.com/adamrk/tonic-rpc/tree/main/example).
100//! Further examples are available in the [tests folder](https://github.com/adamrk/tonic-rpc/tree/main/tonic-rpc/tests).
101//!
102//! # Encodings
103//! Multiple codecs are available for serializing the RPC request/response types.
104//! Each codec is enabled by a [feature flag](https://doc.rust-lang.org/cargo/reference/features.html#the-features-section).
105//! **At least one of these features must be enabled.**
106//! - **`bincode`** - using [`bincode`](https://crates.io/crates/bincode)
107//! - **`cbor`** - using [`serde_cbor`](https://crates.io/crates/serde_cbor)
108//! - **`json`** - using [`serde_json`](https://crates.io/crates/serde_json)
109//! - **`messagepack`** - using [`rmp-serde`](https://crates.io/crates/rmp-serde)
110//!
111//! E.g. To use the encode using `cbor`, use the attribute
112//! ```ignore
113//! #[tonic_rpc::tonic_rpc(cbor)]
114//! ```
115//! and include
116//! ```toml
117//! tonic-rpc = { version = "0.2", features = [ "cbor" ]}
118//! ```
119//! in `Cargo.toml`.
120//!
121//! # Streaming
122//! Streaming can be added on the client or server side by adding the attributes
123//! `#[client_streaming]` or `#[server_streaming]` to a function in the service trait.
124//! These behave the same as if the `stream` keyword were added to a `proto` definition.
125//!
126//! Examples that use streaming can be found in the [tests folder](https://github.com/adamrk/tonic-rpc/tree/main/tonic-rpc/tests).
127//!
128//! # Request/Response types
129//!
130//! The traits and functions generated by `tonic-rpc` will be transformations
131//! of the methods defined in the [`tonic_rpc`] trait that have been modified to
132//! add handling of `gRPC` request/response types, async, and streaming.
133//!
134//! This is a summary of how signatures are transformed:
135//!
136//! ## Arguments
137//! ```ignore
138//! fn f(x: X, y:Y) -> ..
139//! ```
140//! becomes
141//! ```ignore
142//! async fn f(&self, arg: tonic::Request<(X,Y)>) -> ..
143//! ```
144//!
145//! ## Return value
146//! ```ignore
147//! fn f(..) -> Z
148//! ```
149//! becomes
150//! ```ignore
151//! async fn f(..) -> Result<tonic::Response<Z>, tonic::Status>
152//! ```
153//!
154//! ## Streaming arguments
155//! ```ignore
156//! #[client_streaming]
157//! fn f(x:X) -> ..
158//! ```
159//! becomes
160//! ```ignore
161//! async fn f(&self, arg: tonic::Request<tonic::Streaming<X>>) -> ..
162//! ```
163//!
164//! ## Streaming return value
165//! ```ignore
166//! #[server_streaming]
167//! fn f(..) -> Z
168//! ```
169//! becomes
170//! ```ignore
171//! type FStream: Stream<Item = Result<Z, tonic::Status>>;
172//!
173//! async fn f(..) -> Result::<tonic::Response<Self::FStream>, tonic::Status>
174//! ```
175//!
176
177#![cfg_attr(docsrs, feature(doc_cfg))]
178
179pub use tonic_rpc_macro::tonic_rpc;
180
181pub mod codec;