1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
//! A simple RPC library to be used together with `prost` for defining type-safe RPC services.
//!
//! This library lets you generate traits for implementing a generic RPC mechanism using Protobuf as
//! the schema language.  You have to supply your own underlying transport mechanism, for example
//! WebSockets, UNIX pipes, HTTP, etc.
//!
//! You probably want to use this library together with `prost-simple-rpc-build` to generate the
//! code for all of the traits defined in this crate.
//!
//! # Usage
//!
//! Start by defining a schema for your service in e.g. `src/schema/echo/service.proto`:
//!
//! ```proto
//! syntax = "proto3";
//!
//! package echo;
//!
//! // The Echo service. This service returns back the same data that it is given.
//! service Echo {
//!     // Echoes back the data sent, unmodified.
//!     rpc Echo (EchoRequest) returns (EchoResponse);
//! }
//!
//! // The request for an `Echo.Echo` call.
//! message EchoRequest {
//!     // The data to be echoed back.
//!     bytes data = 1;
//! }
//!
//! // The response for an `Echo.Echo` call.
//! message EchoResponse {
//!     // The echoed back data from `EchoRequest.data`.
//!     bytes data = 1;
//! }
//! ```
//!
//! Use `prost`, `prost-build` and `prost-simple-rpc-build` to generate Rust code for this service, by
//! putting this in your `build.rs`:
//!
//! ```rust,ignore
//! extern crate prost_build;
//! extern crate prost_simple_rpc_build;
//!
//! fn main() {
//!     prost_build::Config::new()
//!         .service_generator(Box::new(prost_simple_rpc_build::ServiceGenerator::new()))
//!         .compile_protos(
//!             &["src/schema/echo/service.proto"],
//!             &["src/schema"],
//!         )
//!         .unwrap();
//! }
//! ```
//!
//! Then, include the generated code in your Rust build, for example in `main.rs`.  There are a bunch of
//! extra crate dependencies for the generated code:
//!
//! ```rust,ignore
//! extern crate bytes;
//! extern crate failure;
//! extern crate futures;
//! extern crate prost;
//! #[macro_use]
//! extern crate prost_derive;
//! extern crate prost_simple_rpc;
//! extern crate tokio;
//!
//! mod schema {
//!     pub mod echo {
//!         include!(concat!(env!("OUT_DIR"), "/echo.rs"));
//!     }
//! }
//!
//! fn main() {
//!     // ...
//! }
//! ```
//!
//! ## Client
//!
//! Let's say you want to create a client for your service.  You need to implement a `Handler` that
//! handles the transport for your client calls.  Let's imagine you have some form of `WebSockets`
//! transport:
//!
//! ```rust,ignore
//! struct WebSocketTransport { /* ... */ }
//!
//! impl prost_simple_rpc::handler::Handler for WebSocketTransport {
//!     // From our imaginary websocket library:
//!     type Error = websocket::Error;
//!     // This type is generated by prost-simple-rpc:
//!     type Descriptor = schema::echo::EchoDescriptor;
//!     // From our imaginary websocket library:
//!     type CallFuture = websocket::Future;
//!
//!     /// Perform a raw call to the specified service and method.
//!     fn call(
//!         &mut self,
//!         method: <Self::Descriptor as descriptor::ServiceDescriptor>::Method,
//!         input: bytes::Bytes,
//!     ) -> Self::CallFuture {
//!         // You can use information from the descriptors to include in the request:
//!         self.websocket.call(Self::Descriptor::name(), method.name(), input)
//!     }
//! }
//! ```
//!
//! You can now use this handler with the client generated by `prost-simple-rpc`:
//!
//! ```rust,ignore
//! fn main() {
//!     let websocket = WebSocketTransport::connect("...");
//!     let client = schema::echo::EchoClient::new(websocket);
//!     let future = client.echo(schema::echo::EchoRequest { /* ... */ });
//!     // ... use the future to wait for a response.
//! }
//! ```
//!
//! ## Server
//!
//! To create a server for your service, start by implementing the generated service trait for the
//! service:
//!
//! ```rust,ignore
//! struct EchoService;
//!
//! #[derive(Debug, Eq, Fail, PartialEq)]
//! #[fail(display = "Error!")]
//! struct Error;
//!
//! impl schema::echo::Echo for EchoService {
//!     // You can supply an error type here if your service can fail.
//!     type Error = Error;
//!     // The future type used in the `echo()` method; you can of course use Box<Future<...>> here
//!     // but this library assumes unboxed futures by default.
//!     type EchoFuture = futures::future::FutureResult<schema::echo::EchoResponse, Self::Error>;
//!
//!     fn echo(&self, input: schema::echo::EchoRequest) -> Self::EchoFuture {
//!         futures::future::ok(schema::echo::EchoResponse { data: input.data })
//!     }
//! }
//! ```
//!
//! You can now wrap this service with the generated server implementation to get something that can be
//! plugged into your preferred routing system:
//!
//! ```rust,ignore
//! fn main() {
//!     let server = schema::echo::EchoServer::new(EchoService);
//!
//!     websocket::spawn_server(move |request| {
//!         // You would probably normally look up the right method descriptor via some kind of routing
//!         // information; here's a hard-coded example:
//!         let method = schema::echo::EchoMethodDescriptor::Echo;
//!
//!         server.call(method, request.data);
//!     });
//! }
//! ```
//!
#![deny(missing_docs)]
#![deny(missing_debug_implementations)]
#![deny(missing_copy_implementations)]
#![deny(trivial_casts)]
#![deny(trivial_numeric_casts)]
#![deny(unsafe_code)]
#![deny(unstable_features)]
#![deny(unused_import_braces)]
#![deny(unused_qualifications)]
#![cfg_attr(feature = "dev", allow(unstable_features))]
#![cfg_attr(feature = "dev", feature(plugin))]
#![cfg_attr(feature = "dev", plugin(clippy))]

extern crate bytes;
extern crate failure;
#[macro_use]
extern crate failure_derive;
extern crate futures;
extern crate prost;

pub mod descriptor;
pub mod error;
pub mod handler;
#[doc(hidden)]
pub mod __rt;