Merge branch 'mod-attrs' into 'master'

Allow attributes on the generated module.

If no doc attribute is present, sets a default doc comment for the module.

See merge request !5
This commit is contained in:
Adam Wright
2016-01-25 06:32:09 +05:30

View File

@@ -10,6 +10,70 @@
#[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)]
@@ -70,6 +134,7 @@ macro_rules! request_variant {
#[macro_export]
macro_rules! rpc {
(
$(#[$($service_attr:tt)*])*
mod $server:ident {
service {
@@ -81,6 +146,7 @@ macro_rules! rpc {
}
) => {
rpc! {
$(#[$($service_attr)*])*
mod $server {
items { }
@@ -97,6 +163,7 @@ macro_rules! rpc {
(
// Names the service
$(#[$($service_attr:tt)*])*
mod $server:ident {
// Include any desired or required items. Conflicts can arise with the following names:
@@ -116,77 +183,80 @@ macro_rules! rpc {
}
}
) => {
#[doc="A module containing an rpc service and client stub."]
pub mod $server {
$($i)*
add_mod_doc! {
{ $(#[$($service_attr)*])* }
pub mod $server {
#[doc="The provided RPC service."]
pub trait Service: Send + Sync {
$(
$(#[$attr])*
fn $fn_name(&self, $($arg:$in_),*) -> $out;
)*
}
$($i)*
define_request!($($fn_name($($in_),*))*);
#[allow(non_camel_case_types)]
#[derive(Debug, Serialize, Deserialize)]
enum __Reply {
$(
$fn_name($out),
)*
}
#[doc="The client stub that makes RPC calls to the server."]
pub struct Client($crate::protocol::Client<__Request, __Reply>);
impl Client {
#[doc="Create a new client that connects to the given address."]
pub fn new<A>(addr: A, timeout: ::std::option::Option<::std::time::Duration>)
-> $crate::Result<Self>
where A: ::std::net::ToSocketAddrs,
{
let inner = try!($crate::protocol::Client::new(addr, timeout));
Ok(Client(inner))
#[doc="The provided RPC service."]
pub trait Service: Send + Sync {
$(
$(#[$attr])*
fn $fn_name(&self, $($arg:$in_),*) -> $out;
)*
}
client_methods!(
define_request!($($fn_name($($in_),*))*);
#[allow(non_camel_case_types)]
#[derive(Debug, Serialize, Deserialize)]
enum __Reply {
$(
{ $(#[$attr])* }
$fn_name($($arg: $in_),*) -> $out
$fn_name($out),
)*
);
}
}
struct __Server<S: 'static + Service>(S);
#[doc="The client stub that makes RPC calls to the server."]
pub struct Client($crate::protocol::Client<__Request, __Reply>);
impl<S> $crate::protocol::Serve for __Server<S>
where S: 'static + Service
{
type Request = __Request;
type Reply = __Reply;
fn serve(&self, request: __Request) -> __Reply {
match request {
impl Client {
#[doc="Create a new client that connects to the given address."]
pub fn new<A>(addr: A, timeout: ::std::option::Option<::std::time::Duration>)
-> $crate::Result<Self>
where A: ::std::net::ToSocketAddrs,
{
let inner = try!($crate::protocol::Client::new(addr, timeout));
Ok(Client(inner))
}
client_methods!(
$(
request_variant!($fn_name $($arg),*) =>
__Reply::$fn_name((self.0).$fn_name($($arg),*)),
)*
{ $(#[$attr])* }
$fn_name($($arg: $in_),*) -> $out
)*
);
}
struct __Server<S: 'static + Service>(S);
impl<S> $crate::protocol::Serve for __Server<S>
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<A, S>(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<A, S>(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)))
}
}
}
}
@@ -202,6 +272,8 @@ mod test {
}
rpc! {
#[deny(missing_docs)]
#[doc="Hello"]
mod my_server {
items {
#[derive(PartialEq, Debug, Serialize, Deserialize)]
@@ -245,7 +317,7 @@ mod test {
// Tests a service definition with a fn that takes no args
rpc! {
mod foo {
mod qux {
service {
rpc hello() -> String;
}
@@ -254,6 +326,22 @@ mod test {
// Tests a service definition with an import
rpc! {
mod foo {
items {
use std::collections::HashMap;
}
service {
#[doc="Hello bob"]
#[inline(always)]
rpc baz(s: String) -> HashMap<String, String>;
}
}
}
// Tests a service definition with an attribute but no doc comment
rpc! {
#[deny(missing_docs)]
mod bar {
items {
use std::collections::HashMap;
@@ -261,8 +349,35 @@ mod test {
service {
#[doc="Hello bob"]
#[inline(always)]
rpc baz(s: String) -> HashMap<String, String>;
}
}
}
// Tests a service definition with an attribute and a doc comment
rpc! {
#[deny(missing_docs)]
#[doc="Hello bob"]
#[allow(unused)]
mod baz {
items {
use std::collections::HashMap;
#[derive(Debug)]
pub struct Debuggable;
}
service {
#[doc="Hello bob"]
#[inline(always)]
rpc baz(s: String) -> HashMap<String, String>;
}
}
}
#[test]
fn debug() {
println!("{:?}", baz::Debuggable);
}
}