mirror of
https://github.com/OMGeeky/tarpc.git
synced 2026-01-03 09:58:21 +01:00
Clean up the syntax; add the README.md (I forgot to git add it last time)
This commit is contained in:
44
tarpc/README.md
Normal file
44
tarpc/README.md
Normal file
@@ -0,0 +1,44 @@
|
||||
## tarpc
|
||||
|
||||
tarpc is an RPC framework for rust with a focus on ease of use. Defining and implementing an echo-like server can be done in just a few lines of code:
|
||||
|
||||
```rust
|
||||
#![feature(custom_derive, plugin)]
|
||||
#![plugin(serde_macros)]
|
||||
#[macro_use]
|
||||
extern crate tarpc;
|
||||
extern crate serde;
|
||||
|
||||
rpc! {
|
||||
mod hello_service {
|
||||
service {
|
||||
hello(name: String) -> String;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl hello_service::Service for () {
|
||||
fn hello(&self, name: String) -> String {
|
||||
format!("Hello, {}!", s)
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let server_handle = hello_service::serve("0.0.0.0:0", ()).unwrap();
|
||||
let client = hello_service::Client::new(server_handle.local_addr()).unwrap();
|
||||
assert_eq!("Hello, Mom!".into(), client.hello("Mom".into()).unwrap());
|
||||
drop(client);
|
||||
server_handle.shutdown();
|
||||
}
|
||||
```
|
||||
|
||||
The `rpc!` macro generates a module in the current module. In the above example, the module is named `hello_service`. This module will contain a `Client` type, a `Service` trait, and a `serve` function. `serve` can be used to start a server listening on a tcp port. A `Client` can connect to such a service. Any type implementing the `Service` trait can be passed to `serve`. These generated types are specific to the echo service, and make it easy and ergonomic to write servers without dealing with sockets or serialization directly. See the tarpc_examples package for more sophisticated examples.
|
||||
|
||||
## Planned Improvements (actively being worked on)
|
||||
|
||||
- Automatically reconnect on the client side when the connection cuts out.
|
||||
- Allow omitting the return type in rpc definitions when the type is `()`.
|
||||
- Allow users to specify imports inside the `rpc!` macro
|
||||
- Support arbitrary serialization. (currently `serde_json` is used for all serialization)
|
||||
- Support asynchronous server implementations (currently thread per connection).
|
||||
- Support doc comments on rpc method definitions
|
||||
@@ -8,10 +8,14 @@
|
||||
//! # #![plugin(serde_macros)]
|
||||
//! # #[macro_use] extern crate tarpc;
|
||||
//! # extern crate serde;
|
||||
//! rpc_service!(my_server:
|
||||
//! rpc hello(name: String) -> String;
|
||||
//! rpc add(x: i32, y: i32) -> i32;
|
||||
//! );
|
||||
//! rpc! {
|
||||
//! mod my_server {
|
||||
//! service {
|
||||
//! hello(name: String) -> String;
|
||||
//! add(x: i32, y: i32) -> i32;
|
||||
//! }
|
||||
//! }
|
||||
//! }
|
||||
//!
|
||||
//! use self::my_server::*;
|
||||
//!
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
#[macro_export]
|
||||
macro_rules! as_item { ($i:item) => {$i} }
|
||||
|
||||
// Required because if-let can't be used with irrefutable patterns, so it needs to be special
|
||||
// Required because if-let can't be used with irrefutable patterns, so it needs
|
||||
// to be special
|
||||
// cased.
|
||||
#[macro_export]
|
||||
macro_rules! request_fns {
|
||||
@@ -48,11 +49,46 @@ macro_rules! request_variant {
|
||||
|
||||
// The main macro that creates RPC services.
|
||||
#[macro_export]
|
||||
macro_rules! rpc_service { ($server:ident:
|
||||
$( rpc $fn_name:ident( $( $arg:ident : $in_:ty ),* ) -> $out:ty;)*) => {
|
||||
macro_rules! rpc {
|
||||
(
|
||||
mod $server:ident {
|
||||
|
||||
service {
|
||||
$( $fn_name:ident( $( $arg:ident : $in_:ty ),* ) -> $out:ty;)*
|
||||
}
|
||||
}
|
||||
) => {
|
||||
rpc! {
|
||||
mod $server {
|
||||
|
||||
items { }
|
||||
|
||||
service { $( $fn_name($($arg: $in_),*) -> $out;)* }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
(
|
||||
// Names the service
|
||||
mod $server:ident {
|
||||
|
||||
// Include any desired or required items. Conflicts can arise with the following names:
|
||||
// 1. Service
|
||||
// 2. Client
|
||||
// 3. serve
|
||||
// 4. __Reply
|
||||
// 5. __Request
|
||||
items { $($i:item)* }
|
||||
|
||||
// List any rpc methods: rpc foo(arg1: Arg1, ..., argN: ArgN) -> Out
|
||||
service { $( $fn_name:ident( $( $arg:ident : $in_:ty ),* ) -> $out:ty;)* }
|
||||
}
|
||||
) => {
|
||||
#[doc="A module containing an rpc service and client stub."]
|
||||
pub mod $server {
|
||||
|
||||
$($i)*
|
||||
|
||||
#[doc="The provided RPC service."]
|
||||
pub trait Service: Send + Sync {
|
||||
$(
|
||||
@@ -115,22 +151,27 @@ macro_rules! rpc_service { ($server:ident:
|
||||
#[cfg(test)]
|
||||
#[allow(dead_code)]
|
||||
mod test {
|
||||
rpc_service!(my_server:
|
||||
rpc hello(foo: super::Foo) -> super::Foo;
|
||||
rpc! {
|
||||
mod my_server {
|
||||
items {
|
||||
#[derive(PartialEq, Debug, Serialize, Deserialize)]
|
||||
pub struct Foo {
|
||||
pub message: String
|
||||
}
|
||||
}
|
||||
|
||||
rpc add(x: i32, y: i32) -> i32;
|
||||
);
|
||||
service {
|
||||
hello(foo: Foo) -> Foo;
|
||||
add(x: i32, y: i32) -> i32;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
use self::my_server::*;
|
||||
|
||||
#[derive(PartialEq, Debug, Serialize, Deserialize)]
|
||||
pub struct Foo {
|
||||
message: String
|
||||
}
|
||||
|
||||
impl Service for () {
|
||||
fn hello(&self, s: Foo) -> Foo {
|
||||
Foo{message: format!("Hello, {}", &s.message)}
|
||||
Foo { message: format!("Hello, {}", &s.message) }
|
||||
}
|
||||
|
||||
fn add(&self, x: i32, y: i32) -> i32 {
|
||||
@@ -145,15 +186,32 @@ mod test {
|
||||
let shutdown = my_server::serve(addr, ()).unwrap();
|
||||
let client = Client::new(addr).unwrap();
|
||||
assert_eq!(3, client.add(1, 2).unwrap());
|
||||
let foo = Foo{message: "Adam".into()};
|
||||
let want = Foo{message: format!("Hello, {}", &foo.message)};
|
||||
assert_eq!(want, client.hello(Foo{message: "Adam".into()}).unwrap());
|
||||
let foo = Foo { message: "Adam".into() };
|
||||
let want = Foo { message: format!("Hello, {}", &foo.message) };
|
||||
assert_eq!(want, client.hello(Foo { message: "Adam".into() }).unwrap());
|
||||
drop(client);
|
||||
shutdown.shutdown();
|
||||
}
|
||||
|
||||
// This is a test of a service with a fn that takes no args
|
||||
rpc_service! {foo:
|
||||
rpc hello() -> String;
|
||||
// Tests a service definition with a fn that takes no args
|
||||
rpc! {
|
||||
mod foo {
|
||||
service {
|
||||
hello() -> String;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Tests a service definition with an import
|
||||
rpc! {
|
||||
mod bar {
|
||||
items {
|
||||
use std::collections::HashMap;
|
||||
}
|
||||
|
||||
service {
|
||||
baz(s: String) -> HashMap<String, String>;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user