diff --git a/README.md b/README.md index 1384825..b68d6fd 100644 --- a/README.md +++ b/README.md @@ -9,11 +9,9 @@ tarpc is an RPC framework for rust with a focus on ease of use. Defining and imp extern crate tarpc; extern crate serde; -rpc! { - mod hello_service { - service { - rpc hello(name: String) -> String; - } +mod hello_service { + service! { + rpc hello(name: String) -> String; } } @@ -33,11 +31,18 @@ fn main() { } ``` -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. +The `service!` macro expands to a collection of items that collectively form an rpc service. In the +above example, the macro is called within the `hello_service` module. 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. ## Additional Features - Imports can be specified in an `item {}` block that appears above the `service {}` block. -- Attributes can be specified on rpc methods. These will be included on both the `Service` trait methods as well as on the `Client`'s stub methods. +- Attributes can be specified on rpc methods. These will be included on both the `Service` trait + methods as well as on the `Client`'s stub methods. ## Planned Improvements (actively being worked on) - Automatically reconnect on the client side when the connection cuts out. diff --git a/tarpc/src/lib.rs b/tarpc/src/lib.rs index 2f6755b..e597ca9 100644 --- a/tarpc/src/lib.rs +++ b/tarpc/src/lib.rs @@ -15,12 +15,10 @@ //! # #![plugin(serde_macros)] //! # #[macro_use] extern crate tarpc; //! # extern crate serde; -//! rpc! { -//! mod my_server { -//! service { -//! rpc hello(name: String) -> String; -//! rpc add(x: i32, y: i32) -> i32; -//! } +//! mod my_server { +//! service! { +//! rpc hello(name: String) -> String; +//! rpc add(x: i32, y: i32) -> i32; //! } //! } //! diff --git a/tarpc/src/macros.rs b/tarpc/src/macros.rs index b5195f1..a0fd95b 100644 --- a/tarpc/src/macros.rs +++ b/tarpc/src/macros.rs @@ -10,70 +10,6 @@ #[macro_export] macro_rules! as_item { ($i:item) => {$i} } -// Inserts a placeholder doc comment for the module if it's missing -#[doc(hidden)] -#[macro_export] -macro_rules! add_mod_doc { - // If nothing left, return - ( - @rec - { $(#[$done:meta])* } - { } - $i:item - ) => { - $(#[$done])* - #[doc="A module containing an rpc service and client stub."] - $i - }; - - // If we find a doc attribute, return - ( - @rec - { $(#[$done:meta])* } - { - #[doc=$doc:expr] - $(#[$rest:meta])* - } - $i:item - ) => { - $(#[$done])* - #[doc=$doc] - $(#[$rest])* - $i - }; - - // If we don't find a doc attribute, keep going - ( - @rec - { $(#[$($done:tt)*])* } - { - #[$($attr:tt)*] - $($rest:tt)* - } - $i:item - ) => { - add_mod_doc! { - @rec - { $(#[$($done)*])* #[$($attr)*] } - { $($rest)* } - $i - } - }; - - // Entry - ( - { $(#[$($attr:tt)*])* } - $i:item - ) => { - add_mod_doc! { - @rec - {} - { $(#[$($attr)*])* } - $i - } - }; -} - // Required because if-let can't be used with irrefutable patterns, so it needs // to be special cased. #[doc(hidden)] @@ -176,178 +112,126 @@ macro_rules! request_variant { // The main macro that creates RPC services. #[macro_export] -macro_rules! rpc { +macro_rules! service { ( - $(#[$($service_attr:tt)*])* - mod $server:ident { - - service { - $( - $(#[$attr:meta])* - rpc $fn_name:ident( $( $arg:ident : $in_:ty ),* ) -> $out:ty; - )* - } - } + // List any rpc methods: rpc foo(arg1: Arg1, ..., argN: ArgN) -> Out + $( + $(#[$attr:meta])* + rpc $fn_name:ident( $( $arg:ident : $in_:ty ),* ) -> $out:ty; + )* ) => { - rpc! { - $(#[$($service_attr)*])* - mod $server { + #[doc="The provided RPC service."] + pub trait Service: Send + Sync { + $( + $(#[$attr])* + fn $fn_name(&self, $($arg:$in_),*) -> $out; + )* + } - items { } - - service { - $( - $(#[$attr])* - rpc $fn_name($($arg: $in_),*) -> $out; - )* + impl
Service for P
+ where P: Send + Sync + ::std::ops::Deref Service for P
- where P: Send + Sync + ::std::ops::Deref $crate::protocol::Serve for __Server
+ where S: 'static + Service
+ {
+ type Request = __Request;
+ type Reply = __Reply;
+ fn serve(&self, request: __Request) -> __Reply {
+ match request {
+ $(
+ request_variant!($fn_name $($arg),*) =>
+ __Reply::$fn_name((self.0).$fn_name($($arg),*)),
+ )*
+ }
}
}
- ) => {
- add_mod_doc! {
- { $(#[$($service_attr)*])* }
- pub mod $server {
-
- $($i)*
-
- #[doc="The provided RPC service."]
- pub trait Service: Send + Sync {
- $(
- $(#[$attr])*
- fn $fn_name(&self, $($arg:$in_),*) -> $out;
- )*
- }
-
- impl $crate::protocol::Serve for __Server
- where S: 'static + Service
- {
- type Request = __Request;
- type Reply = __Reply;
- fn serve(&self, request: __Request) -> __Reply {
- match request {
- $(
- request_variant!($fn_name $($arg),*) =>
- __Reply::$fn_name((self.0).$fn_name($($arg),*)),
- )*
- }
- }
- }
-
- #[doc="Start a running service."]
- pub fn serve(addr: A,
- service: S,
- read_timeout: ::std::option::Option<::std::time::Duration>)
- -> $crate::Result<$crate::protocol::ServeHandle>
- where A: ::std::net::ToSocketAddrs,
- S: 'static + Service
- {
- let server = ::std::sync::Arc::new(__Server(service));
- Ok(try!($crate::protocol::serve_async(addr, server, read_timeout)))
- }
- }
+ #[doc="Start a running service."]
+ pub fn serve(addr: A,
+ service: S,
+ read_timeout: ::std::option::Option<::std::time::Duration>)
+ -> $crate::Result<$crate::protocol::ServeHandle>
+ where A: ::std::net::ToSocketAddrs,
+ S: 'static + Service
+ {
+ let server = ::std::sync::Arc::new(__Server(service));
+ Ok(try!($crate::protocol::serve_async(addr, server, read_timeout)))
}
}
}
@@ -363,28 +247,23 @@ mod test {
Some(Duration::from_secs(5))
}
- rpc! {
- #[deny(missing_docs)]
- #[doc="Hello"]
- mod my_server {
- items {
- #[derive(PartialEq, Debug, Serialize, Deserialize)]
- pub struct Foo {
- pub message: String
- }
- }
+ #[derive(PartialEq, Debug, Serialize, Deserialize)]
+ pub struct Foo {
+ pub message: String
+ }
- service {
- rpc hello(foo: Foo) -> Foo;
- rpc add(x: i32, y: i32) -> i32;
- }
+ mod my_server {
+ use super::Foo;
+
+ service! {
+ rpc hello(foo: Foo) -> Foo;
+ rpc add(x: i32, y: i32) -> i32;
}
}
- use self::my_server::*;
-
struct Server;
- impl Service for Server {
+
+ impl my_server::Service for Server {
fn hello(&self, s: Foo) -> Foo {
Foo { message: format!("Hello, {}", &s.message) }
}
@@ -396,7 +275,7 @@ mod test {
#[test]
fn serve_arc_server() {
- serve("localhost:0", ::std::sync::Arc::new(Server), None)
+ my_server::serve("localhost:0", ::std::sync::Arc::new(Server), None)
.unwrap()
.shutdown();
}
@@ -404,7 +283,7 @@ mod test {
#[test]
fn simple() {
let handle = my_server::serve( "localhost:0", Server, test_timeout()).unwrap();
- let client = Client::new(handle.local_addr(), None).unwrap();
+ let client = my_server::Client::new(handle.local_addr(), None).unwrap();
assert_eq!(3, client.add(1, 2).unwrap());
let foo = Foo { message: "Adam".into() };
let want = Foo { message: format!("Hello, {}", &foo.message) };
@@ -416,7 +295,7 @@ mod test {
#[test]
fn simple_async() {
let handle = my_server::serve("localhost:0", Server, test_timeout()).unwrap();
- let client = AsyncClient::new(handle.local_addr(), None).unwrap();
+ let client = my_server::AsyncClient::new(handle.local_addr(), None).unwrap();
assert_eq!(3, client.add(1, 2).get().unwrap());
let foo = Foo { message: "Adam".into() };
let want = Foo { message: format!("Hello, {}", &foo.message) };
@@ -425,63 +304,48 @@ mod test {
handle.shutdown();
}
- // Tests a service definition with a fn that takes no args
- rpc! {
- mod qux {
- service {
- rpc hello() -> String;
- }
+ /// Tests a service definition with a fn that takes no args
+ mod qux {
+ service! {
+ rpc hello() -> String;
}
}
- // Tests a service definition with an import
- rpc! {
- mod foo {
- items {
- use std::collections::HashMap;
- }
+ /// Tests a service definition with an import
+ mod foo {
+ use std::collections::HashMap;
- service {
- #[doc="Hello bob"]
- #[inline(always)]
- rpc baz(s: String) -> HashMap