From 865712f36eed32d3d9f4f4268b3672ed8fdcc2ed Mon Sep 17 00:00:00 2001 From: Adam Wright Date: Wed, 11 Jan 2017 23:26:48 -0800 Subject: [PATCH] First pass at some more detailed documentation --- README.md | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 58 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 3c7c5af..feda7c4 100644 --- a/README.md +++ b/README.md @@ -83,7 +83,7 @@ also a `ServiceExt` trait that provides starter `fn`s for services, with an umbrella impl for all services. These generated types make it easy and ergonomic to write servers without dealing with sockets or serialization directly. Simply implement one of the generated traits, and you're off to the -races! See the tarpc_examples package for more examples. +races! See the `tarpc_examples` package for more examples. ## Example: Futures @@ -131,11 +131,67 @@ fn main() { } ``` +## Tips + +### Sync vs Futures + +A single `service!` invocation generates code for both synchronous and future-based applications. +It's up to the user whether they want to implement the sync API or the futures API. The sync API has +the simplest programming model, at the cost of some overhead - each RPC is handled in its own +thread. The futures API is based on tokio and can run on any tokio-compatible executor. This mean a +service that implements the futures API for a tarpc service can run on a single thread, avoiding +context switches and the memory overhead of having a thread per RPC. + +### Errors + +All generated tarpc RPC methods return either `tarpc::Result` or something like `Future`. The error type defaults to `tarpc::util::Never` (a wrapper for `!` which implements +`std::error::Error`) if no error type is explicitly specified in the `service!` macro invocation. An +error type can be specified like so: + +```rust +use tarpc::util::Message; + +service! { + rpc hello(name: String) -> String | Message +} +``` + +`tarpc::util::Message` is just a wrapper around string that implements `std::error::Error` provided +for service implementations that don't require complex error handling. The pipe is used as syntax +for specifying the error type in a way that's agnostic of whether the service implementation is +synchronous or future-based. Note that in the simpler examples in the readme, no pipe is used, and +the macro automatically chooses `tarpc::util::Never` as the error type. + +The above declaration would produce the following synchronous service trait: + +```rust +impl SyncService for HelloServer { + fn hello(&self, name: String) -> Result { + Ok(format!("Hello, {}!", name)) + } +} +``` + +and the following future-based trait: + +```rust +impl FutureService for HelloServer { + type HelloFut = futures::Finished; + + fn hello(&mut self, name: String) -> Self::HelloFut { + futures::finished(format!("Hello, {}!", name)) + } +} +``` + ## Documentation + Use `cargo doc` as you normally would to see the documentation created for all items expanded by a `service!` invocation. ## Additional Features + - Concurrent requests from a single client. - Compatible with tokio services. - Run any number of clients and services on a single event loop. @@ -145,6 +201,7 @@ items expanded by a `service!` invocation. services' trait methods as well as on the clients' stub methods. ## Gaps/Potential Improvements (not necessarily actively being worked on) + - Configurable server rate limiting. - Automatic client retries with exponential backoff when server is busy. - Load balancing