Allow attributes on the generated module.

If no doc attribute is present, sets a default doc comment for the module.
This commit is contained in:
Tim Kuehn
2016-01-17 23:21:27 -08:00
parent 8125f7dead
commit 166fbf6891
2 changed files with 169 additions and 60 deletions

View File

@@ -42,7 +42,7 @@
//! ```
#![deny(missing_docs)]
#![feature(custom_derive, plugin)]
#![feature(custom_derive, plugin, trace_macros)]
#![plugin(serde_macros)]
extern crate serde;

View File

@@ -1,7 +1,73 @@
trace_macros!(true);
#[doc(hidden)]
#[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)]
@@ -62,6 +128,7 @@ macro_rules! request_variant {
#[macro_export]
macro_rules! rpc {
(
$(#[$($service_attr:tt)*])*
mod $server:ident {
service {
@@ -73,6 +140,7 @@ macro_rules! rpc {
}
) => {
rpc! {
$(#[$($service_attr)*])*
mod $server {
items { }
@@ -89,6 +157,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:
@@ -108,77 +177,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)))
}
}
}
}
@@ -194,6 +266,8 @@ mod test {
}
rpc! {
#[deny(missing_docs)]
#[doc="Hello"]
mod my_server {
items {
#[derive(PartialEq, Debug, Serialize, Deserialize)]
@@ -237,7 +311,7 @@ mod test {
// Tests a service definition with a fn that takes no args
rpc! {
mod foo {
mod qux {
service {
rpc hello() -> String;
}
@@ -246,6 +320,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;
@@ -253,6 +343,25 @@ 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;
}
service {
#[doc="Hello bob"]
#[inline(always)]
rpc baz(s: String) -> HashMap<String, String>;
}
}