4 releases
0.2.1 | Feb 6, 2023 |
---|---|
0.2.0 | Sep 20, 2022 |
0.1.1 | Apr 10, 2021 |
0.1.0 | Apr 9, 2021 |
#17 in #bincode
Used in bonerjams-db
22KB
214 lines
tonic-rpc
is a macro that generates the traits and stubs used by tonic
from Rust definitions instead of proto
files.
This means that you can get all the benefits
of tonic
while using regular Rust types and without needing to use proto
files or build scripts.
Of course, this comes at the sacrifice of interoperability.
Alternatives
tarpc
is an excellent RPC library that also defines services
as a Rust trait.
Required dependencies
tonic = "0.8.3"
tonic-rpc = { version = "0.2.1", features = [ <enabled-codecs> ] }
Example
Instead of defining a proto
file, define a service as a trait:
#[tonic_rpc::tonic_rpc(json)]
trait Increment {
fn increment(arg: i32) -> i32;
}
The attribute #[tonic_rpc(json)]
indicates that this service
will serialize the requests and responses using json
.
Other encodings are available
.
The arguments and return values for each function must implement
serde::Serialize
and serde::Deserialize
.
The service can be implemented by defining an impl
:
struct State;
#[tonic::async_trait]
impl increment_server::Increment for State {
async fn increment(
&self,
request: tonic::Request<i32>,
) -> Result<tonic::Response<i32>, tonic::Status> {
Ok(tonic::Response::new(request.into_inner() + 1))
}
}
And a server and client can be run:
async fn run_client_server() {
let mut listener = tokio::net::TcpListener::bind("[::1]:0").await.unwrap();
let addr = listener.local_addr().unwrap();
tokio::spawn(async move {
tonic::transport::Server::builder()
.add_service(increment_server::IncrementServer::new(State))
.serve_with_incoming(tokio_stream::wrappers::TcpListenerStream::new(listener))
.await
});
let mut client = increment_client::IncrementClient::connect(format!("http://{}", addr))
.await
.unwrap();
let response = client.increment(32).await.unwrap().into_inner();
assert_eq!(33, response);
}
The full example is available here. Further examples are available in the tests folder.
Encodings
Multiple codecs are available for serializing the RPC request/response types. Each codec is enabled by a feature flag. At least one of these features must be enabled.
bincode
- usingbincode
cbor
- usingserde_cbor
json
- usingserde_json
messagepack
- usingrmp-serde
E.g. To use the encode using cbor
, use the attribute
#[tonic_rpc::tonic_rpc(cbor)]
and include
tonic-rpc = { version = "0.2.1", features = [ "cbor" ]}
in Cargo.toml
.
Streaming
Streaming can be added on the client or server side by adding the attributes
#[client_streaming]
or #[server_streaming]
to a function in the service trait.
These behave the same as if the stream
keyword were added to a proto
definition.
Examples that use streaming can be found in the tests folder.
Request/Response types
The traits and functions generated by tonic-rpc
will be transformations
of the methods defined in the tonic_rpc
trait that have been modified to
add handling of gRPC
request/response types, async, and streaming.
This is a summary of how signatures are transformed:
Arguments
fn f(x: X, y:Y) -> ..
becomes
async fn f(&self, arg: tonic::Request<(X,Y)>) -> ..
Return value
fn f(..) -> Z
becomes
async fn f(..) -> Result<tonic::Response<Z>, tonic::Status>
Streaming arguments
#[client_streaming]
fn f(x:X) -> ..
becomes
async fn f(&self, arg: tonic::Request<tonic::Streaming<X>>) -> ..
Streaming return value
#[server_streaming]
fn f(..) -> Z
becomes
type FStream: Stream<Item = Result<Z, tonic::Status>>;
async fn f(..) -> Result::<tonic::Response<Self::FStream>, tonic::Status>
Dependencies
~6–12MB
~142K SLoC