Extend snake_to_camel plugin to replace {} in the doc string with the original snake-cased ident. (#50)

* Extend snake_to_camel plugin to replace {} in the doc string with the origin snake-cased ident.

Also, track tokio-rs master.

This is really ad-hoc, undiscoverable, and unintuitive, but there's no way to programmatically create doc strings
in regular code, and I want to produce better doc strings for the associated types.

Given `fn foo_bar`:

Before: `/// The type of future returned by the function of the same name.`
After: ``/// The type of future returned by `{}`.``
    => `/// The type of future returned by foo_bar.`

* Fix some docs

* Use a helper fn on pipeline::Frame instead of handrolled match.

* Don't hide docs for ClientFuture.

It's exposed in the Connect impl of FutureService -- the tradeoff for not generating *another* item -- and hiding it breaks doc links.

* Formatting

* Rename snake_to_camel plugin => tarpc-plugins

* Update README

* Mangle a lot of names in macro expansion.

To lower the chance of any issues, prefix idents in service expansion with __tarpc_service.
In future_enum, prefix with __future_enum. The pattern is basically __macro_name_ident.

Any imported enum variant will conflict with a let binding or a function arg, so we basically
can't use any generic idents at all. Example:

    enum Req { request(..) }
    use self::Req::request;

    fn make_request(request: Request) { ... }

                    ^^^^^^^ conflict here

Additionally, suffix generated associated types with Fut to avoid conflicts with camelcased rpcs.
Why someone would do that, I don't know, but we shouldn't allow that wart.
This commit is contained in:
Tim
2016-09-14 01:19:24 -07:00
committed by GitHub
parent 54017839d1
commit be5f55c5f6
20 changed files with 422 additions and 381 deletions

View File

@@ -13,7 +13,7 @@ description = "An RPC framework for Rust with a focus on ease of use."
[dependencies]
bincode = "0.6"
byteorder = "0.5"
bytes = "0.3"
bytes = { git = "https://github.com/carllerche/bytes" }
futures = { git = "https://github.com/alexcrichton/futures-rs" }
futures-cpupool = { git = "https://github.com/alexcrichton/futures-rs" }
lazy_static = "0.2"
@@ -21,7 +21,7 @@ log = "0.3"
scoped-pool = "1.0"
serde = "0.8"
serde_derive = "0.8"
snake_to_camel = { path = "src/snake_to_camel" }
tarpc-plugins = { path = "src/plugins" }
take = "0.1"
tokio-service = { git = "https://github.com/tokio-rs/tokio-service" }
tokio-proto = { git = "https://github.com/tokio-rs/tokio-proto" }

View File

@@ -38,14 +38,14 @@ Add to your `Cargo.toml` dependencies:
```toml
tarpc = { git = "https://github.com/google/tarpc" }
snake_to_camel = { git = "https://github.com/google/tarpc" }
tarpc-plugins = { git = "https://github.com/google/tarpc" }
```
## Example
```rust
// required by `FutureClient` (not used in this example)
#![feature(conservative_impl_trait, plugin)]
#![plugin(snake_to_camel)]
#![plugin(tarpc_plugins)]
extern crate futures;
#[macro_use]

View File

@@ -4,7 +4,7 @@
// This file may not be copied, modified, or distributed except according to those terms.
#![feature(plugin, conservative_impl_trait, test)]
#![plugin(snake_to_camel)]
#![plugin(tarpc_plugins)]
#[macro_use]
extern crate tarpc;
@@ -26,8 +26,8 @@ service! {
struct Server;
impl FutureService for Server {
type Ack = futures::Finished<(), Never>;
fn ack(&self) -> Self::Ack {
type AckFut = futures::Finished<(), Never>;
fn ack(&self) -> Self::AckFut {
futures::finished(())
}
}

View File

@@ -4,7 +4,7 @@
// This file may not be copied, modified, or distributed except according to those terms.
#![feature(inclusive_range_syntax, conservative_impl_trait, plugin)]
#![plugin(snake_to_camel)]
#![plugin(tarpc_plugins)]
extern crate chrono;
extern crate env_logger;
@@ -36,9 +36,9 @@ impl Server {
}
impl FutureService for Server {
type Read = CpuFuture<Vec<u8>, Never>;
type ReadFut = CpuFuture<Vec<u8>, Never>;
fn read(&self, size: u32) -> Self::Read {
fn read(&self, size: u32) -> Self::ReadFut {
self.0
.spawn(futures::lazy(move || {
let mut vec: Vec<u8> = Vec::with_capacity(size as usize);
@@ -105,7 +105,7 @@ const MAX_CONCURRENCY: u32 = 100;
fn main() {
let _ = env_logger::init();
let server = Server::new().listen("localhost:0").unwrap();
let server = Server::new().listen("localhost:0").wait().unwrap();
println!("Server listening on {}.", server.local_addr());
let clients: Vec<_> = (1...5)
.map(|i| {

View File

@@ -4,7 +4,7 @@
// This file may not be copied, modified, or distributed except according to those terms.
#![feature(conservative_impl_trait, plugin)]
#![plugin(snake_to_camel)]
#![plugin(tarpc_plugins)]
extern crate env_logger;
extern crate futures;
@@ -48,8 +48,9 @@ struct Subscriber {
}
impl subscriber::FutureService for Subscriber {
type Receive = futures::Finished<(), Never>;
fn receive(&self, message: String) -> Self::Receive {
type ReceiveFut = futures::Finished<(), Never>;
fn receive(&self, message: String) -> Self::ReceiveFut {
println!("{} received message: {}", self.id, message);
futures::finished(())
}
@@ -62,6 +63,7 @@ impl Subscriber {
publisher: publisher.clone(),
}
.listen("localhost:0")
.wait()
.unwrap();
publisher.subscribe(&id, &subscriber.local_addr()).unwrap();
subscriber
@@ -80,9 +82,9 @@ impl Publisher {
}
impl publisher::FutureService for Publisher {
type Broadcast = BoxFuture<(), Never>;
type BroadcastFut = BoxFuture<(), Never>;
fn broadcast(&self, message: String) -> Self::Broadcast {
fn broadcast(&self, message: String) -> Self::BroadcastFut {
futures::collect(self.clients
.lock()
.unwrap()
@@ -94,9 +96,9 @@ impl publisher::FutureService for Publisher {
.boxed()
}
type Subscribe = BoxFuture<(), Message>;
type SubscribeFut = BoxFuture<(), Message>;
fn subscribe(&self, id: u32, address: SocketAddr) -> BoxFuture<(), Message> {
fn subscribe(&self, id: u32, address: SocketAddr) -> Self::SubscribeFut {
let clients = self.clients.clone();
subscriber::FutureClient::connect(&address)
.map(move |subscriber| {
@@ -108,9 +110,9 @@ impl publisher::FutureService for Publisher {
.boxed()
}
type Unsubscribe = BoxFuture<(), Never>;
type UnsubscribeFut = BoxFuture<(), Never>;
fn unsubscribe(&self, id: u32) -> BoxFuture<(), Never> {
fn unsubscribe(&self, id: u32) -> Self::UnsubscribeFut {
println!("Unsubscribing {}", id);
self.clients.lock().unwrap().remove(&id).unwrap();
futures::finished(()).boxed()
@@ -119,7 +121,7 @@ impl publisher::FutureService for Publisher {
fn main() {
let _ = env_logger::init();
let publisher = Publisher::new().listen("localhost:0").unwrap();
let publisher = Publisher::new().listen("localhost:0").wait().unwrap();
let publisher = publisher::SyncClient::connect(publisher.local_addr()).unwrap();
let _subscriber1 = Subscriber::new(0, publisher.clone());
let _subscriber2 = Subscriber::new(1, publisher.clone());

View File

@@ -4,7 +4,7 @@
// This file may not be copied, modified, or distributed except according to those terms.
#![feature(conservative_impl_trait, plugin)]
#![plugin(snake_to_camel)]
#![plugin(tarpc_plugins)]
extern crate futures;
#[macro_use]
@@ -28,7 +28,7 @@ impl SyncService for HelloServer {
fn main() {
let addr = "localhost:10000";
let _server = HelloServer.listen(addr).unwrap();
let _server = HelloServer.listen(addr);
let client = SyncClient::connect(addr).unwrap();
println!("{}", client.hello(&"Mom".to_string()).unwrap());
}

View File

@@ -4,7 +4,7 @@
// This file may not be copied, modified, or distributed except according to those terms.
#![feature(conservative_impl_trait, plugin, rustc_macro)]
#![plugin(snake_to_camel)]
#![plugin(tarpc_plugins)]
extern crate futures;
#[macro_use]
@@ -50,7 +50,7 @@ impl SyncService for HelloServer {
fn main() {
let addr = "localhost:10000";
let _server = HelloServer.listen(addr).unwrap();
let _server = HelloServer.listen(addr);
let client = SyncClient::connect(addr).unwrap();
println!("{}", client.hello(&"Mom".to_string()).unwrap());
println!("{}", client.hello(&"".to_string()).unwrap_err());

View File

@@ -4,15 +4,15 @@
// This file may not be copied, modified, or distributed except according to those terms.
#![feature(conservative_impl_trait, plugin)]
#![plugin(snake_to_camel)]
#![plugin(tarpc_plugins)]
#[macro_use]
extern crate tarpc;
extern crate futures;
use futures::{BoxFuture, Future};
use add::{FutureService as AddService, FutureServiceExt as AddExt};
use double::{FutureService as DoubleService, FutureServiceExt as DoubleExt};
use add::{FutureService as AddFutureService, FutureServiceExt as AddExt};
use double::{FutureService as DoubleFutureService, FutureServiceExt as DoubleExt};
use tarpc::util::{Never, Message};
use tarpc::future::Connect as Fc;
use tarpc::sync::Connect as Sc;
@@ -36,10 +36,10 @@ pub mod double {
#[derive(Clone)]
struct AddServer;
impl AddService for AddServer {
type Add = futures::Finished<i32, Never>;
impl AddFutureService for AddServer {
type AddFut = futures::Finished<i32, Never>;
fn add(&self, x: i32, y: i32) -> Self::Add {
fn add(&self, x: i32, y: i32) -> Self::AddFut {
futures::finished(x + y)
}
}
@@ -49,10 +49,10 @@ struct DoubleServer {
client: add::FutureClient,
}
impl DoubleService for DoubleServer {
type Double = BoxFuture<i32, Message>;
impl DoubleFutureService for DoubleServer {
type DoubleFut = BoxFuture<i32, Message>;
fn double(&self, x: i32) -> Self::Double {
fn double(&self, x: i32) -> Self::DoubleFut {
self.client
.add(&x, &x)
.map_err(|e| e.to_string().into())
@@ -61,10 +61,10 @@ impl DoubleService for DoubleServer {
}
fn main() {
let add = AddServer.listen("localhost:0").unwrap();
let add = AddServer.listen("localhost:0").wait().unwrap();
let add_client = add::FutureClient::connect(add.local_addr()).wait().unwrap();
let double = DoubleServer { client: add_client };
let double = double.listen("localhost:0").unwrap();
let double = double.listen("localhost:0").wait().unwrap();
let double_client = double::SyncClient::connect(double.local_addr()).unwrap();
for i in 0..5 {

View File

@@ -4,7 +4,7 @@
// This file may not be copied, modified, or distributed except according to those terms.
#![feature(conservative_impl_trait, plugin)]
#![plugin(snake_to_camel)]
#![plugin(tarpc_plugins)]
#[macro_use]
extern crate lazy_static;
@@ -18,6 +18,7 @@ use std::time;
use std::net;
use std::thread;
use std::io::{Read, Write, stdout};
use futures::Future;
use tarpc::util::Never;
use tarpc::sync::Connect;
@@ -41,9 +42,9 @@ service! {
struct Server;
impl FutureService for Server {
type Read = futures::Finished<Arc<Vec<u8>>, Never>;
type ReadFut = futures::Finished<Arc<Vec<u8>>, Never>;
fn read(&self) -> Self::Read {
fn read(&self) -> Self::ReadFut {
futures::finished(BUF.clone())
}
}
@@ -51,7 +52,7 @@ impl FutureService for Server {
const CHUNK_SIZE: u32 = 1 << 19;
fn bench_tarpc(target: u64) {
let handle = Server.listen("localhost:0").unwrap();
let handle = Server.listen("localhost:0").wait().unwrap();
let client = SyncClient::connect(handle.local_addr()).unwrap();
let start = time::Instant::now();
let mut nread = 0;

View File

@@ -4,7 +4,7 @@
// This file may not be copied, modified, or distributed except according to those terms.
#![feature(conservative_impl_trait, plugin)]
#![plugin(snake_to_camel)]
#![plugin(tarpc_plugins)]
#[macro_use]
extern crate log;
@@ -16,6 +16,7 @@ extern crate futures;
use bar::FutureServiceExt as BarExt;
use baz::FutureServiceExt as BazExt;
use futures::Future;
use tarpc::util::Never;
use tarpc::sync::Connect;
@@ -28,9 +29,9 @@ mod bar {
#[derive(Clone)]
struct Bar;
impl bar::FutureService for Bar {
type Bar = futures::Finished<i32, Never>;
type BarFut = futures::Finished<i32, Never>;
fn bar(&self, i: i32) -> Self::Bar {
fn bar(&self, i: i32) -> Self::BarFut {
futures::finished(i)
}
}
@@ -44,9 +45,9 @@ mod baz {
#[derive(Clone)]
struct Baz;
impl baz::FutureService for Baz {
type Baz = futures::Finished<String, Never>;
type BazFut = futures::Finished<String, Never>;
fn baz(&self, s: String) -> Self::Baz {
fn baz(&self, s: String) -> Self::BazFut {
futures::finished(format!("Hello, {}!", s))
}
}
@@ -57,8 +58,8 @@ macro_rules! pos {
fn main() {
let _ = env_logger::init();
let bar = Bar.listen("localhost:0").unwrap();
let baz = Baz.listen("localhost:0").unwrap();
let bar = Bar.listen("localhost:0").wait().unwrap();
let baz = Baz.listen("localhost:0").wait().unwrap();
let bar_client = bar::SyncClient::connect(bar.local_addr()).unwrap();
let baz_client = baz::SyncClient::connect(baz.local_addr()).unwrap();

View File

@@ -4,26 +4,34 @@
// This file may not be copied, modified, or distributed except according to those terms.
use Packet;
use futures::BoxFuture;
use futures::{Async, BoxFuture};
use futures::stream::Empty;
use std::fmt;
use std::io;
use tokio_service::Service;
use tokio_proto::pipeline;
use tokio_service::Service;
use util::Never;
/// A thin wrapper around `pipeline::Client` that handles Serialization.
/// A client `Service` that writes and reads bytes.
///
/// Typically, this would be combined with a serialization pre-processing step
/// and a deserialization post-processing step.
#[derive(Clone)]
pub struct Client {
inner: pipeline::Client<Packet, Vec<u8>, Empty<(), io::Error>, io::Error>,
inner: pipeline::Client<Packet, Vec<u8>, Empty<Never, io::Error>, io::Error>,
}
impl Service for Client {
type Req = Packet;
type Resp = Vec<u8>;
type Request = Packet;
type Response = Vec<u8>;
type Error = io::Error;
type Fut = BoxFuture<Vec<u8>, io::Error>;
type Future = BoxFuture<Vec<u8>, io::Error>;
fn call(&self, request: Packet) -> Self::Fut {
fn poll_ready(&self) -> Async<()> {
Async::Ready(())
}
fn call(&self, request: Packet) -> Self::Future {
self.inner.call(pipeline::Message::WithoutBody(request))
}
}
@@ -36,28 +44,42 @@ impl fmt::Debug for Client {
/// Exposes a trait for connecting asynchronously to servers.
pub mod future {
use futures::{self, BoxFuture, Future};
use futures::{self, Async, Future};
use protocol::{LOOP_HANDLE, TarpcTransport};
use std::cell::RefCell;
use std::io;
use std::net::SocketAddr;
use super::Client;
use take::Take;
use tokio_core::TcpStream;
use tokio_core::net::TcpStream;
use tokio_proto::pipeline;
/// Types that can connect to a server asynchronously.
pub trait Connect: Sized {
/// The type of the future returned when calling connect.
type Fut: Future<Item=Self, Error=io::Error>;
type Fut: Future<Item = Self, Error = io::Error>;
/// Connects to a server located at the given address.
fn connect(addr: &SocketAddr) -> Self::Fut;
}
/// A future that resolves to a `Client` or an `io::Error`.
#[doc(hidden)]
pub type ClientFuture = futures::Map<BoxFuture<TcpStream, io::Error>, fn(TcpStream) -> Client>;
pub struct ClientFuture {
inner: futures::Oneshot<io::Result<Client>>,
}
impl Future for ClientFuture {
type Item = Client;
type Error = io::Error;
fn poll(&mut self) -> futures::Poll<Self::Item, Self::Error> {
match self.inner.poll().unwrap() {
Async::Ready(Ok(client)) => Ok(Async::Ready(client)),
Async::Ready(Err(err)) => Err(err),
Async::NotReady => Ok(Async::NotReady),
}
}
}
impl Connect for Client {
type Fut = ClientFuture;
@@ -65,14 +87,21 @@ pub mod future {
/// Starts an event loop on a thread and registers a new client
/// connected to the given address.
fn connect(addr: &SocketAddr) -> ClientFuture {
fn connect(stream: TcpStream) -> Client {
let loop_handle = LOOP_HANDLE.clone();
let service = Take::new(move || Ok(TarpcTransport::new(stream)));
Client { inner: pipeline::connect(loop_handle, service) }
}
LOOP_HANDLE.clone()
.tcp_connect(addr)
.map(connect)
let addr = *addr;
let (tx, rx) = futures::oneshot();
LOOP_HANDLE.spawn(move |handle| {
let handle2 = handle.clone();
TcpStream::connect(&addr, handle)
.and_then(move |tcp| {
let tcp = RefCell::new(Some(tcp));
let c = try!(pipeline::connect(&handle2, move || {
Ok(TarpcTransport::new(tcp.borrow_mut().take().unwrap()))
}));
Ok(Client { inner: c })
})
.then(|client| Ok(tx.complete(client)))
});
ClientFuture { inner: rx }
}
}
}
@@ -105,4 +134,3 @@ pub mod sync {
}
}
}

View File

@@ -4,10 +4,10 @@
// This file may not be copied, modified, or distributed except according to those terms.
use bincode;
use serde::{Deserialize, Serialize};
use std::{fmt, io};
use std::error::Error as StdError;
use tokio_proto::pipeline;
use serde::{Deserialize, Serialize};
/// All errors that can occur during the use of tarpc.
#[derive(Debug)]
@@ -121,4 +121,3 @@ pub enum WireError<E>
pub trait SerializableError: StdError + Deserialize + Serialize + Send + 'static {}
impl<E: StdError + Deserialize + Serialize + Send + 'static> SerializableError for E {}

View File

@@ -29,7 +29,7 @@
//! ```
//! // required by `FutureClient` (not used in this example)
//! #![feature(conservative_impl_trait, plugin)]
//! #![plugin(snake_to_camel)]
//! #![plugin(tarpc_plugins)]
//!
//! #[macro_use]
//! extern crate tarpc;
@@ -52,7 +52,7 @@
//!
//! fn main() {
//! let addr = "localhost:10000";
//! let _server = HelloServer.listen(addr).unwrap();
//! let _server = HelloServer.listen(addr);
//! let client = SyncClient::connect(addr).unwrap();
//! println!("{}", client.hello(&"Mom".to_string()).unwrap());
//! }
@@ -60,7 +60,7 @@
//!
#![deny(missing_docs)]
#![feature(plugin, question_mark, conservative_impl_trait, never_type, rustc_macro)]
#![plugin(snake_to_camel)]
#![plugin(tarpc_plugins)]
extern crate bincode;
extern crate byteorder;
@@ -98,7 +98,7 @@ pub use errors::{WireError};
#[doc(hidden)]
pub use protocol::{Packet, deserialize};
#[doc(hidden)]
pub use server::{SerializeFuture, SerializedReply, listen, serialize_reply};
pub use server::{ListenFuture, SerializeFuture, SerializedReply, listen, serialize_reply};
/// Provides some utility error types, as well as a trait for spawning futures on the default event
/// loop.

View File

@@ -3,6 +3,12 @@
// Licensed under the MIT License, <LICENSE or http://opensource.org/licenses/MIT>.
// This file may not be copied, modified, or distributed except according to those terms.
#[doc(hidden)]
#[macro_export]
macro_rules! as_item {
($i:item) => {$i};
}
/// Creates an enum where each variant contains a `Future`. The created enum impls `Future`.
/// Useful when a fn needs to return possibly many different types of futures.
#[macro_export]
@@ -14,23 +20,11 @@ macro_rules! future_enum {
$($variant:ident($inner:ty)),*
}
} => {
$(#[$attr])*
pub enum $name<$($tp),*> {
$(#[$attrv])*
$($variant($inner)),*
}
impl<__T, __E, $($tp),*> $crate::futures::Future for $name<$($tp),*>
where __T: ::std::marker::Send + 'static,
$($inner: $crate::futures::Future<Item=__T, Error=__E>),*
{
type Item = __T;
type Error = __E;
fn poll(&mut self) -> $crate::futures::Poll<Self::Item, Self::Error> {
match *self {
$($name::$variant(ref mut f) => $crate::futures::Future::poll(f)),*
}
future_enum! {
$(#[$attr:meta])*
(pub) enum $name<$($tp),*> {
$(#[$attrv])*
$($variant($inner)),*
}
}
};
@@ -40,19 +34,37 @@ macro_rules! future_enum {
$(#[$attrv:meta])*
$($variant:ident($inner:ty)),*
}
} => {
future_enum! {
$(#[$attr:meta])*
() enum $name<$($tp),*> {
$(#[$attrv])*
$($variant($inner)),*
}
}
};
{
$(#[$attr:meta])*
($($vis:tt)*) enum $name:ident<$($tp:ident),*> {
$(#[$attrv:meta])*
$($variant:ident($inner:ty)),*
}
} => {
$(#[$attr])*
enum $name<$($tp),*> {
$(#[$attrv])*
$($variant($inner)),*
as_item! {
$($vis)* enum $name<$($tp),*> {
$(#[$attrv])*
$($variant($inner)),*
}
}
impl<__T, __E, $($tp),*> $crate::futures::Future for $name<$($tp),*>
where __T: ::std::marker::Send + 'static,
$($inner: $crate::futures::Future<Item=__T, Error=__E>),*
#[allow(non_camel_case_types)]
impl<__future_enum_T, __future_enum_E, $($tp),*> $crate::futures::Future for $name<$($tp),*>
where __future_enum_T: Send + 'static,
$($inner: $crate::futures::Future<Item=__future_enum_T, Error=__future_enum_E>),*
{
type Item = __T;
type Error = __E;
type Item = __future_enum_T;
type Error = __future_enum_E;
fn poll(&mut self) -> $crate::futures::Poll<Self::Item, Self::Error> {
match *self {
@@ -63,12 +75,6 @@ macro_rules! future_enum {
}
}
#[doc(hidden)]
#[macro_export]
macro_rules! as_item {
($i:item) => {$i};
}
#[doc(hidden)]
#[macro_export]
macro_rules! impl_serialize {
@@ -76,18 +82,18 @@ macro_rules! impl_serialize {
as_item! {
impl$($lifetime)* $crate::serde::Serialize for $impler$($lifetime)* {
#[inline]
fn serialize<S>(&self, serializer: &mut S) -> ::std::result::Result<(), S::Error>
fn serialize<S>(&self, __impl_serialize_serializer: &mut S) -> ::std::result::Result<(), S::Error>
where S: $crate::serde::Serializer
{
match *self {
$(
$impler::$name(ref field) =>
$impler::$name(ref __impl_serialize_field) =>
$crate::serde::Serializer::serialize_newtype_variant(
serializer,
__impl_serialize_serializer,
stringify!($impler),
$n,
stringify!($name),
field,
__impl_serialize_field,
)
),*
}
@@ -117,42 +123,43 @@ macro_rules! impl_serialize {
macro_rules! impl_deserialize {
($impler:ident, $(@($name:ident $n:expr))* -- #($_n:expr) ) => (
impl $crate::serde::Deserialize for $impler {
#[inline]
fn deserialize<D>(deserializer: &mut D)
-> ::std::result::Result<$impler, D::Error>
where D: $crate::serde::Deserializer
#[allow(non_camel_case_types)]
fn deserialize<__impl_deserialize_D>(__impl_deserialize_deserializer: &mut __impl_deserialize_D)
-> ::std::result::Result<$impler, __impl_deserialize_D::Error>
where __impl_deserialize_D: $crate::serde::Deserializer
{
#[allow(non_camel_case_types, unused)]
enum Field {
enum __impl_deserialize_Field {
$($name),*
}
impl $crate::serde::Deserialize for Field {
impl $crate::serde::Deserialize for __impl_deserialize_Field {
#[inline]
fn deserialize<D>(deserializer: &mut D)
-> ::std::result::Result<Field, D::Error>
fn deserialize<D>(__impl_deserialize_deserializer: &mut D)
-> ::std::result::Result<__impl_deserialize_Field, D::Error>
where D: $crate::serde::Deserializer
{
struct FieldVisitor;
impl $crate::serde::de::Visitor for FieldVisitor {
type Value = Field;
struct __impl_deserialize_FieldVisitor;
impl $crate::serde::de::Visitor for __impl_deserialize_FieldVisitor {
type Value = __impl_deserialize_Field;
#[inline]
fn visit_usize<E>(&mut self, value: usize)
-> ::std::result::Result<Field, E>
fn visit_usize<E>(&mut self, __impl_deserialize_value: usize)
-> ::std::result::Result<__impl_deserialize_Field, E>
where E: $crate::serde::de::Error,
{
$(
if value == $n {
return ::std::result::Result::Ok(Field::$name);
if __impl_deserialize_value == $n {
return ::std::result::Result::Ok(__impl_deserialize_Field::$name);
}
)*
::std::result::Result::Err(
$crate::serde::de::Error::custom(
format!("No variants have a value of {}!", value))
format!("No variants have a value of {}!", __impl_deserialize_value))
)
}
}
deserializer.deserialize_struct_field(FieldVisitor)
__impl_deserialize_deserializer.deserialize_struct_field(__impl_deserialize_FieldVisitor)
}
}
@@ -167,7 +174,7 @@ macro_rules! impl_deserialize {
{
match try!(visitor.visit_variant()) {
$(
Field::$name => {
__impl_deserialize_Field::$name => {
let val = try!(visitor.visit_newtype());
::std::result::Result::Ok($impler::$name(val))
}
@@ -180,7 +187,7 @@ macro_rules! impl_deserialize {
stringify!($name)
),*
];
deserializer.deserialize_enum(stringify!($impler), VARIANTS, Visitor)
__impl_deserialize_deserializer.deserialize_enum(stringify!($impler), VARIANTS, Visitor)
}
}
);
@@ -198,7 +205,7 @@ macro_rules! impl_deserialize {
///
/// ```
/// # #![feature(conservative_impl_trait, plugin)]
/// # #![plugin(snake_to_camel)]
/// # #![plugin(tarpc_plugins)]
/// # #[macro_use] extern crate tarpc;
/// # fn main() {}
/// # service! {
@@ -226,7 +233,7 @@ macro_rules! impl_deserialize {
///
#[macro_export]
macro_rules! service {
// Entry point
// Entry point
(
$(
$(#[$attr:meta])*
@@ -240,7 +247,7 @@ macro_rules! service {
)*
}}
};
// Pattern for when the next rpc has an implicit unit return type and no error type.
// Pattern for when the next rpc has an implicit unit return type and no error type.
(
{
$(#[$attr:meta])*
@@ -259,7 +266,7 @@ macro_rules! service {
rpc $fn_name( $( $arg : $in_ ),* ) -> () | $crate::util::Never;
}
};
// Pattern for when the next rpc has an explicit return type and no error type.
// Pattern for when the next rpc has an explicit return type and no error type.
(
{
$(#[$attr:meta])*
@@ -278,7 +285,7 @@ macro_rules! service {
rpc $fn_name( $( $arg : $in_ ),* ) -> $out | $crate::util::Never;
}
};
// Pattern for when the next rpc has an implicit unit return type and an explicit error type.
// Pattern for when the next rpc has an implicit unit return type and an explicit error type.
(
{
$(#[$attr:meta])*
@@ -297,7 +304,7 @@ macro_rules! service {
rpc $fn_name( $( $arg : $in_ ),* ) -> () | $error;
}
};
// Pattern for when the next rpc has an explicit return type and an explicit error type.
// Pattern for when the next rpc has an explicit return type and an explicit error type.
(
{
$(#[$attr:meta])*
@@ -316,7 +323,7 @@ macro_rules! service {
rpc $fn_name( $( $arg : $in_ ),* ) -> $out | $error;
}
};
// Pattern for when all return types have been expanded
// Pattern for when all return types have been expanded
(
{ } // none left to expand
$(
@@ -358,9 +365,9 @@ macro_rules! service {
}
) => {
/// Defines the `Future` RPC service. Implementors must be `Clone`, `Send`, and `'static`,
/// as required by `tokio_proto::NewService`. This is required so that the service can be used
/// to respond to multiple requests concurrently.
/// Defines the `Future` RPC service. Implementors must be `Clone`, `Send`, and `'static`,
/// as required by `tokio_proto::NewService`. This is required so that the service can be used
/// to respond to multiple requests concurrently.
pub trait FutureService:
::std::marker::Send +
::std::clone::Clone +
@@ -369,7 +376,7 @@ macro_rules! service {
$(
snake_to_camel! {
/// The type of future returned by the fn of the same name.
/// The type of future returned by `{}`.
type $fn_name: $crate::futures::Future<Item=$out, Error=$error>;
}
@@ -381,73 +388,79 @@ macro_rules! service {
/// Provides a function for starting the service. This is a separate trait from
/// `FutureService` to prevent collisions with the names of RPCs.
pub trait FutureServiceExt: FutureService {
/// Registers the service with the given registry, listening on the given address.
fn listen<L>(self, addr: L)
-> ::std::io::Result<$crate::tokio_proto::server::ServerHandle>
/// Spawns the service, binding to the given address and running on
/// the default tokio `Loop`.
fn listen<L>(self, addr: L) -> $crate::ListenFuture
where L: ::std::net::ToSocketAddrs
{
return $crate::listen(addr, __AsyncServer(self));
return $crate::listen(addr, __tarpc_service_AsyncServer(self));
#[allow(non_camel_case_types)]
#[derive(Clone)]
struct __AsyncServer<S>(S);
struct __tarpc_service_AsyncServer<S>(S);
impl<S> ::std::fmt::Debug for __AsyncServer<S> {
impl<S> ::std::fmt::Debug for __tarpc_service_AsyncServer<S> {
fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
write!(fmt, "__AsyncServer {{ .. }}")
write!(fmt, "__tarpc_service_AsyncServer {{ .. }}")
}
}
#[allow(non_camel_case_types)]
enum Reply<TyParamS: FutureService> {
enum __tarpc_service_Reply<__tarpc_service_S: FutureService> {
DeserializeError($crate::SerializeFuture),
$($fn_name($crate::futures::Then<$crate::futures::MapErr<ty_snake_to_camel!(TyParamS::$fn_name),
$($fn_name($crate::futures::Then<$crate::futures::MapErr<ty_snake_to_camel!(__tarpc_service_S::$fn_name),
fn($error) -> $crate::WireError<$error>>,
$crate::SerializeFuture,
fn(::std::result::Result<$out, $crate::WireError<$error>>)
-> $crate::SerializeFuture>)),*
}
impl<S: FutureService> $crate::futures::Future for Reply<S> {
impl<S: FutureService> $crate::futures::Future for __tarpc_service_Reply<S> {
type Item = $crate::SerializedReply;
type Error = ::std::io::Error;
fn poll(&mut self) -> $crate::futures::Poll<Self::Item, Self::Error> {
match *self {
Reply::DeserializeError(ref mut f) => $crate::futures::Future::poll(f),
$(Reply::$fn_name(ref mut f) => $crate::futures::Future::poll(f)),*
__tarpc_service_Reply::DeserializeError(ref mut f) => $crate::futures::Future::poll(f),
$(__tarpc_service_Reply::$fn_name(ref mut f) => $crate::futures::Future::poll(f)),*
}
}
}
impl<S> $crate::tokio_service::Service for __AsyncServer<S>
where S: FutureService
#[allow(non_camel_case_types)]
impl<__tarpc_service_S> $crate::tokio_service::Service for __tarpc_service_AsyncServer<__tarpc_service_S>
where __tarpc_service_S: FutureService
{
type Req = ::std::vec::Vec<u8>;
type Resp = $crate::SerializedReply;
type Request = ::std::vec::Vec<u8>;
type Response = $crate::SerializedReply;
type Error = ::std::io::Error;
type Fut = Reply<S>;
type Future = __tarpc_service_Reply<__tarpc_service_S>;
fn call(&self, req: Self::Req) -> Self::Fut {
fn poll_ready(&self) -> $crate::futures::Async<()> {
$crate::futures::Async::Ready(())
}
fn call(&self, req: Self::Request) -> Self::Future {
#[allow(non_camel_case_types, unused)]
#[derive(Debug)]
enum __ServerSideRequest {
enum __tarpc_service_ServerSideRequest {
$(
$fn_name(( $($in_,)* ))
),*
}
impl_deserialize!(__ServerSideRequest, $($fn_name(($($in_),*)))*);
impl_deserialize!(__tarpc_service_ServerSideRequest, $($fn_name(($($in_),*)))*);
let request = $crate::deserialize(&req);
let request: __ServerSideRequest = match request {
::std::result::Result::Ok(request) => request,
::std::result::Result::Err(e) => {
return Reply::DeserializeError(deserialize_error(e));
let __tarpc_service_request = $crate::deserialize(&req);
let __tarpc_service_request: __tarpc_service_ServerSideRequest = match __tarpc_service_request {
::std::result::Result::Ok(__tarpc_service_request) => __tarpc_service_request,
::std::result::Result::Err(__tarpc_service_e) => {
return __tarpc_service_Reply::DeserializeError(deserialize_error(__tarpc_service_e));
}
};
match request {$(
__ServerSideRequest::$fn_name(( $($arg,)* )) => {
match __tarpc_service_request {$(
__tarpc_service_ServerSideRequest::$fn_name(( $($arg,)* )) => {
const SERIALIZE: fn(::std::result::Result<$out, $crate::WireError<$error>>)
-> $crate::SerializeFuture = $crate::serialize_reply;
const TO_APP: fn($error) -> $crate::WireError<$error> = $crate::WireError::App;
@@ -455,23 +468,23 @@ macro_rules! service {
let reply = FutureService::$fn_name(&self.0, $($arg),*);
let reply = $crate::futures::Future::map_err(reply, TO_APP);
let reply = $crate::futures::Future::then(reply, SERIALIZE);
return Reply::$fn_name(reply);
return __tarpc_service_Reply::$fn_name(reply);
}
)*}
#[inline]
fn deserialize_error<E: ::std::error::Error>(e: E) -> $crate::SerializeFuture {
let err = $crate::WireError::ServerDeserialize::<$crate::util::Never>(e.to_string());
$crate::serialize_reply(::std::result::Result::Err::<(), _>(err))
fn deserialize_error<E: ::std::error::Error>(__tarpc_service_e: E) -> $crate::SerializeFuture {
let __tarpc_service_err = $crate::WireError::ServerDeserialize::<$crate::util::Never>(__tarpc_service_e.to_string());
$crate::serialize_reply(::std::result::Result::Err::<(), _>(__tarpc_service_err))
}
}
}
}
}
/// Defines the blocking RPC service. Must be `Clone`, `Send`, and `'static`,
/// as required by `tokio_proto::NewService`. This is required so that the service can be used
/// to respond to multiple requests concurrently.
/// Defines the blocking RPC service. Must be `Clone`, `Send`, and `'static`,
/// as required by `tokio_proto::NewService`. This is required so that the service can be used
/// to respond to multiple requests concurrently.
pub trait SyncService:
::std::marker::Send +
::std::clone::Clone +
@@ -486,23 +499,27 @@ macro_rules! service {
/// Provides a function for starting the service. This is a separate trait from
/// `SyncService` to prevent collisions with the names of RPCs.
pub trait SyncServiceExt: SyncService {
/// Registers the service with the given registry, listening on the given address.
/// Spawns the service, binding to the given address and running on
/// the default tokio `Loop`.
fn listen<L>(self, addr: L)
-> ::std::io::Result<$crate::tokio_proto::server::ServerHandle>
-> $crate::tokio_proto::server::ServerHandle
where L: ::std::net::ToSocketAddrs
{
let service = __SyncServer {
service: self,
};
return service.listen(addr);
return ::std::result::Result::unwrap($crate::futures::Future::wait(FutureServiceExt::listen(service, addr)));
#[derive(Clone)]
struct __SyncServer<S> {
service: S,
}
impl<S> FutureService for __SyncServer<S> where S: SyncService {
#[allow(non_camel_case_types)]
impl<__tarpc_service_S> FutureService for __SyncServer<__tarpc_service_S>
where __tarpc_service_S: SyncService
{
$(
impl_snake_to_camel! {
type $fn_name =
@@ -517,13 +534,16 @@ macro_rules! service {
// TODO(tikue): what do do if SyncService panics?
unimplemented!()
}
const UNIMPLEMENTED: fn($crate::futures::Canceled) -> $error =
unimplemented;
let (c, p) = $crate::futures::oneshot();
let service = self.clone();
::std::thread::spawn(move || {
let reply = SyncService::$fn_name(&service.service, $($arg),*);
c.complete($crate::futures::IntoFuture::into_future(reply));
});
let p = $crate::futures::Future::map_err(p, unimplemented as fn($crate::futures::Canceled) -> $error);
let p = $crate::futures::Future::map_err(p, UNIMPLEMENTED);
$crate::futures::Future::flatten(p)
}
)*
@@ -536,7 +556,7 @@ macro_rules! service {
#[allow(unused)]
#[derive(Clone, Debug)]
/// The client stub that makes RPC calls to the server. Exposes a blocking interface.
/// The client stub that makes RPC calls to the server. Exposes a blocking interface.
pub struct SyncClient(FutureClient);
impl $crate::sync::Connect for SyncClient {
@@ -544,7 +564,9 @@ macro_rules! service {
where A: ::std::net::ToSocketAddrs,
{
let mut addrs = try!(::std::net::ToSocketAddrs::to_socket_addrs(&addr));
let addr = if let ::std::option::Option::Some(a) = ::std::iter::Iterator::next(&mut addrs) {
let addr = if let ::std::option::Option::Some(a) =
::std::iter::Iterator::next(&mut addrs)
{
a
} else {
return ::std::result::Result::Err(
@@ -564,7 +586,9 @@ macro_rules! service {
#[allow(unused)]
$(#[$attr])*
#[inline]
pub fn $fn_name(&self, $($arg: &$in_),*) -> ::std::result::Result<$out, $crate::Error<$error>> {
pub fn $fn_name(&self, $($arg: &$in_),*)
-> ::std::result::Result<$out, $crate::Error<$error>>
{
let rpc = (self.0).$fn_name($($arg),*);
$crate::futures::Future::wait(rpc)
}
@@ -573,7 +597,7 @@ macro_rules! service {
#[allow(unused)]
#[derive(Clone, Debug)]
/// The client stub that makes RPC calls to the server. Exposes a Future interface.
/// The client stub that makes RPC calls to the server. Exposes a Future interface.
pub struct FutureClient($crate::Client);
impl $crate::future::Connect for FutureClient {
@@ -603,20 +627,20 @@ macro_rules! service {
}
}
let args = ($($arg,)*);
let req = &__ClientSideRequest::$fn_name(&args);
let req = match $crate::Packet::serialize(&req) {
::std::result::Result::Err(e) => return Fut::Failed($crate::futures::failed($crate::Error::ClientSerialize(e))),
::std::result::Result::Ok(req) => req,
let __tarpc_service_args = ($($arg,)*);
let __tarpc_service_req = &__ClientSideRequest::$fn_name(&__tarpc_service_args);
let __tarpc_service_req = match $crate::Packet::serialize(&__tarpc_service_req) {
::std::result::Result::Err(__tarpc_service_e) => return Fut::Failed($crate::futures::failed($crate::Error::ClientSerialize(__tarpc_service_e))),
::std::result::Result::Ok(__tarpc_service_req) => __tarpc_service_req,
};
let fut = $crate::tokio_service::Service::call(&self.0, req);
Fut::Called($crate::futures::Future::then(fut, move |msg| {
let msg: Vec<u8> = try!(msg);
let msg: ::std::result::Result<::std::result::Result<$out, $crate::WireError<$error>>, _>
= $crate::deserialize(&msg);
match msg {
::std::result::Result::Ok(msg) => ::std::result::Result::Ok(try!(msg)),
::std::result::Result::Err(e) => ::std::result::Result::Err($crate::Error::ClientDeserialize(e)),
let __tarpc_service_fut = $crate::tokio_service::Service::call(&self.0, __tarpc_service_req);
Fut::Called($crate::futures::Future::then(__tarpc_service_fut, move |__tarpc_service_msg| {
let __tarpc_service_msg: Vec<u8> = try!(__tarpc_service_msg);
let __tarpc_service_msg: ::std::result::Result<::std::result::Result<$out, $crate::WireError<$error>>, _>
= $crate::deserialize(&__tarpc_service_msg);
match __tarpc_service_msg {
::std::result::Result::Ok(__tarpc_service_msg) => ::std::result::Result::Ok(try!(__tarpc_service_msg)),
::std::result::Result::Err(__tarpc_service_e) => ::std::result::Result::Err($crate::Error::ClientDeserialize(__tarpc_service_e)),
}
}))
}
@@ -625,13 +649,16 @@ macro_rules! service {
}
}
}
// allow dead code; we're just testing that the macro expansion compiles
#[allow(dead_code)]
#[cfg(test)]
mod syntax_test {
use util::Never;
service! {
#[deny(warnings)]
#[allow(non_snake_case)]
rpc TestCamelCaseDoesntConflict();
rpc hello() -> String;
#[doc="attr"]
rpc attr(s: String) -> String;
@@ -659,10 +686,10 @@ mod functional_test {
}
mod sync {
use super::{SyncClient, SyncService, SyncServiceExt};
use super::env_logger;
use sync::Connect;
use util::Never;
use super::env_logger;
use super::{SyncClient, SyncService, SyncServiceExt};
#[derive(Clone, Copy)]
struct Server;
@@ -679,7 +706,7 @@ mod functional_test {
#[test]
fn simple() {
let _ = env_logger::init();
let handle = Server.listen("localhost:0").unwrap();
let handle = Server.listen("localhost:0");
let client = SyncClient::connect(handle.local_addr()).unwrap();
assert_eq!(3, client.add(&1, &2).unwrap());
assert_eq!("Hey, Tim.", client.hey(&"Tim".to_string()).unwrap());
@@ -687,7 +714,7 @@ mod functional_test {
#[test]
fn clone() {
let handle = Server.listen("localhost:0").unwrap();
let handle = Server.listen("localhost:0");
let client1 = SyncClient::connect(handle.local_addr()).unwrap();
let client2 = client1.clone();
assert_eq!(3, client1.add(&1, &2).unwrap());
@@ -697,7 +724,7 @@ mod functional_test {
#[test]
fn other_service() {
let _ = env_logger::init();
let handle = Server.listen("localhost:0").unwrap();
let handle = Server.listen("localhost:0");
let client = super::other_service::SyncClient::connect(handle.local_addr()).unwrap();
match client.foo().err().unwrap() {
::Error::ServerDeserialize(_) => {} // good
@@ -708,24 +735,24 @@ mod functional_test {
mod future {
use future::Connect;
use util::Never;
use futures::{Finished, Future, finished};
use super::env_logger;
use super::{FutureClient, FutureService, FutureServiceExt};
use super::env_logger;
use util::Never;
#[derive(Clone)]
struct Server;
impl FutureService for Server {
type Add = Finished<i32, Never>;
type AddFut = Finished<i32, Never>;
fn add(&self, x: i32, y: i32) -> Self::Add {
fn add(&self, x: i32, y: i32) -> Self::AddFut {
finished(x + y)
}
type Hey = Finished<String, Never>;
type HeyFut = Finished<String, Never>;
fn hey(&self, name: String) -> Self::Hey {
fn hey(&self, name: String) -> Self::HeyFut {
finished(format!("Hey, {}.", name))
}
}
@@ -733,7 +760,7 @@ mod functional_test {
#[test]
fn simple() {
let _ = env_logger::init();
let handle = Server.listen("localhost:0").unwrap();
let handle = Server.listen("localhost:0").wait().unwrap();
let client = FutureClient::connect(handle.local_addr()).wait().unwrap();
assert_eq!(3, client.add(&1, &2).wait().unwrap());
assert_eq!("Hey, Tim.", client.hey(&"Tim".to_string()).wait().unwrap());
@@ -742,7 +769,7 @@ mod functional_test {
#[test]
fn clone() {
let _ = env_logger::init();
let handle = Server.listen("localhost:0").unwrap();
let handle = Server.listen("localhost:0").wait().unwrap();
let client1 = FutureClient::connect(handle.local_addr()).wait().unwrap();
let client2 = client1.clone();
assert_eq!(3, client1.add(&1, &2).wait().unwrap());
@@ -752,7 +779,7 @@ mod functional_test {
#[test]
fn other_service() {
let _ = env_logger::init();
let handle = Server.listen("localhost:0").unwrap();
let handle = Server.listen("localhost:0").wait().unwrap();
let client =
super::other_service::FutureClient::connect(handle.local_addr()).wait().unwrap();
match client.foo().wait().err().unwrap() {
@@ -772,9 +799,9 @@ mod functional_test {
struct ErrorServer;
impl error_service::FutureService for ErrorServer {
type Bar = ::futures::Failed<u32, ::util::Message>;
type BarFut = ::futures::Failed<u32, ::util::Message>;
fn bar(&self) -> Self::Bar {
fn bar(&self) -> Self::BarFut {
info!("Called bar");
failed("lol jk".into())
}
@@ -788,7 +815,7 @@ mod functional_test {
use self::error_service::*;
let _ = env_logger::init();
let handle = ErrorServer.listen("localhost:0").unwrap();
let handle = ErrorServer.listen("localhost:0").wait().unwrap();
let client = FutureClient::connect(handle.local_addr()).wait().unwrap();
client.bar()
.then(move |result| {

View File

@@ -1,5 +1,5 @@
[package]
name = "snake_to_camel"
name = "tarpc-plugins"
version = "0.1.0"
authors = ["Tim Kuehn <tikue@google.com>"]

View File

@@ -6,15 +6,19 @@ extern crate rustc_plugin;
extern crate syntax;
use itertools::Itertools;
use rustc_plugin::Registry;
use syntax::ast::{self, Ident, TraitRef, Ty, TyKind};
use syntax::parse::{self, PResult, token};
use syntax::ast::LitKind::Str;
use syntax::ast::MetaItemKind::NameValue;
use syntax::codemap::Spanned;
use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacEager};
use syntax::parse::{self, token, PResult};
use syntax::ptr::P;
use syntax::parse::parser::{Parser, PathStyle};
use syntax::parse::token::intern_and_get_ident;
use syntax::tokenstream::TokenTree;
use syntax::ext::base::{DummyResult, ExtCtxt, MacEager, MacResult};
use syntax::ext::quote::rt::Span;
use syntax::util::small_vector::SmallVector;
use rustc_plugin::Registry;
fn snake_to_camel(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> Box<MacResult + 'static> {
let mut parser = parse::new_parser_from_tts(cx.parse_sess(), cx.cfg(), tts.into());
@@ -34,7 +38,33 @@ fn snake_to_camel(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> Box<MacResul
return DummyResult::any(sp);
}
convert(&mut item.ident);
let old_ident = convert(&mut item.ident);
// As far as I know, it's not possible in macro_rules! to reference an $ident in a doc string,
// so this is the hacky workaround.
//
// This code looks intimidating, but it's just iterating through the trait item's attributes
// (NameValues), filtering out non-doc attributes, and replacing any {} in the doc string with
// the original, snake_case ident.
for meta_item in item.attrs.iter_mut().map(|attr| &mut attr.node.value) {
let updated = match meta_item.node {
NameValue(ref name, _) if name == "doc" => {
let mut updated = (**meta_item).clone();
if let NameValue(_, Spanned { node: Str(ref mut doc, _), .. }) = updated.node {
let updated_doc = doc.replace("{}", &old_ident);
*doc = intern_and_get_ident(&updated_doc);
} else {
unreachable!()
};
Some(P(updated))
}
_ => None,
};
if let Some(updated) = updated {
*meta_item = updated;
}
}
MacEager::trait_items(SmallVector::one(item))
}
@@ -78,11 +108,9 @@ fn ty_snake_to_camel(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> Box<MacRe
return DummyResult::any(sp);
}
// Find the first non-underscore and add it capitalized.
// Only capitalize the final segment
if let TyKind::Path(_, ref mut path) = ty {
for segment in &mut path.segments {
convert(&mut segment.identifier);
}
convert(&mut path.segments.last_mut().unwrap().identifier);
} else {
unreachable!()
}
@@ -93,38 +121,45 @@ fn ty_snake_to_camel(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> Box<MacRe
}))
}
fn convert(ident: &mut Ident) {
/// Converts an ident in-place to CamelCase and returns the previous ident.
fn convert(ident: &mut Ident) -> String {
let ident_str = ident.to_string();
let mut camel_ty = String::new();
// Find the first non-underscore and add it capitalized.
let mut chars = ident_str.chars();
{
// Find the first non-underscore and add it capitalized.
let mut chars = ident_str.chars();
// Find the first non-underscore char, uppercase it, and append it.
// Guaranteed to succeed because all idents must have at least one non-underscore char.
camel_ty.extend(chars.find(|&c| c != '_').unwrap().to_uppercase());
// Find the first non-underscore char, uppercase it, and append it.
// Guaranteed to succeed because all idents must have at least one non-underscore char.
camel_ty.extend(chars.find(|&c| c != '_').unwrap().to_uppercase());
// When we find an underscore, we remove it and capitalize the next char. To do this,
// we need to ensure the next char is not another underscore.
let mut chars = chars.coalesce(|c1, c2| {
if c1 == '_' && c2 == '_' {
Ok(c1)
} else {
Err((c1, c2))
}
});
// When we find an underscore, we remove it and capitalize the next char. To do this,
// we need to ensure the next char is not another underscore.
let mut chars = chars.coalesce(|c1, c2| {
if c1 == '_' && c2 == '_' {
Ok(c1)
} else {
Err((c1, c2))
}
});
while let Some(c) = chars.next() {
if c != '_' {
camel_ty.push(c);
} else {
if let Some(c) = chars.next() {
camel_ty.extend(c.to_uppercase());
while let Some(c) = chars.next() {
if c != '_' {
camel_ty.push(c);
} else {
if let Some(c) = chars.next() {
camel_ty.extend(c.to_uppercase());
}
}
}
}
// The Fut suffix is hardcoded right now; this macro isn't really meant to be general-purpose.
camel_ty.push_str("Fut");
*ident = Ident::with_empty_ctxt(token::intern(&camel_ty));
ident_str
}
trait ParseTraitRef {

View File

@@ -3,22 +3,24 @@
// Licensed under the MIT License, <LICENSE or http://opensource.org/licenses/MIT>.
// This file may not be copied, modified, or distributed except according to those terms.
use {futures, serde};
use serde;
use futures::{self, Async};
use bincode::{SizeLimit, serde as bincode};
use std::{io, thread};
use std::collections::VecDeque;
use std::sync::mpsc;
use tokio_core::{Loop, LoopHandle};
use tokio_proto::io::{Readiness, Transport};
use util::Never;
use tokio_core::io::{FramedIo, Io};
use tokio_core::reactor::{Core, Remote};
use tokio_proto::pipeline::Frame;
lazy_static! {
#[doc(hidden)]
pub static ref LOOP_HANDLE: LoopHandle = {
pub static ref LOOP_HANDLE: Remote = {
let (tx, rx) = mpsc::channel();
thread::spawn(move || {
let mut lupe = Loop::new().unwrap();
tx.send(lupe.handle()).unwrap();
let mut lupe = Core::new().unwrap();
tx.send(lupe.handle().remote().clone()).unwrap();
// Run forever
lupe.run(futures::empty::<(), !>()).unwrap();
});
@@ -78,46 +80,30 @@ impl<T> TarpcTransport<T> {
}
}
impl<T> Readiness for TarpcTransport<T>
where T: Readiness
impl<T> FramedIo for TarpcTransport<T>
where T: Io
{
fn is_readable(&self) -> bool {
self.stream.is_readable()
type In = Frame<Packet, Never, io::Error>;
type Out = Frame<Vec<u8>, Never, io::Error>;
fn poll_read(&mut self) -> Async<()> {
self.stream.poll_read()
}
fn is_writable(&self) -> bool {
// Always allow writing... this isn't really the best strategy to do in
// practice, but it is the easiest to implement in this case. The
// number of in-flight requests can be controlled using the pipeline
// dispatcher.
true
fn poll_write(&mut self) -> Async<()> {
self.stream.poll_write()
}
}
impl<T> Transport for TarpcTransport<T>
where T: io::Read + io::Write + Readiness,
{
type In = Frame<Packet, io::Error>;
type Out = Frame<Vec<u8>, io::Error>;
fn read(&mut self) -> io::Result<Option<Frame<Vec<u8>, io::Error>>> {
fn read(&mut self) -> io::Result<Async<Frame<Vec<u8>, Never, io::Error>>> {
self.read_state.next(&mut self.stream)
}
fn write(&mut self, req: Frame<Packet, io::Error>) -> io::Result<Option<()>> {
match req {
Frame::Message(msg) => {
self.outbound.push_back(msg);
self.flush()
}
Frame::MessageWithBody(..) => unreachable!(),
Frame::Body(_) => unreachable!(),
Frame::Error(_) => unreachable!(),
Frame::Done => unreachable!(),
}
fn write(&mut self, req: Self::In) -> io::Result<Async<()>> {
self.outbound.push_back(req.unwrap_msg());
self.flush()
}
fn flush(&mut self) -> io::Result<Option<()>> {
fn flush(&mut self) -> io::Result<Async<()>> {
writer::NextWriteState::next(&mut self.head, &mut self.stream, &mut self.outbound)
}
}

View File

@@ -5,39 +5,12 @@
use byteorder::{BigEndian, ReadBytesExt};
use bytes::{MutBuf, Take};
use std::io::{self, Read};
use futures::Async;
use std::io;
use std::mem;
use super::MapNonBlock;
use tokio_proto::TryRead;
use tokio_proto::pipeline::Frame;
pub trait TryRead {
fn try_read_buf<B: MutBuf>(&mut self, buf: &mut B) -> io::Result<Option<usize>>
where Self: Sized
{
// Reads the length of the slice supplied by buf.mut_bytes into the buffer
// This is not guaranteed to consume an entire datagram or segment.
// If your protocol is msg based (instead of continuous stream) you should
// ensure that your buffer is large enough to hold an entire segment
// (1532 bytes if not jumbo frames)
let res = self.try_read(unsafe { buf.mut_bytes() });
if let Ok(Some(cnt)) = res {
unsafe {
buf.advance(cnt);
}
}
res
}
fn try_read(&mut self, buf: &mut [u8]) -> io::Result<Option<usize>>;
}
impl<T: Read> TryRead for T {
fn try_read(&mut self, dst: &mut [u8]) -> io::Result<Option<usize>> {
self.read(dst).map_non_block()
}
}
use util::Never;
#[derive(Debug)]
pub struct U64Reader {
@@ -74,7 +47,7 @@ enum NextReadAction<R> {
Stop(Result<R, io::Error>),
}
trait MutBufExt: MutBuf {
trait MutBufExt: MutBuf + Sized {
type Inner;
fn take(&mut self) -> Self::Inner;
@@ -138,7 +111,7 @@ impl ReadState {
pub fn next<R: TryRead>(&mut self,
socket: &mut R)
-> io::Result<Option<Frame<Vec<u8>, io::Error>>> {
-> io::Result<Async<Frame<Vec<u8>, Never, io::Error>>> {
loop {
let next = match *self {
ReadState::Len(ref mut len) => {
@@ -151,7 +124,7 @@ impl ReadState {
NextReadState::Next(ReadState::Data(Take::new(buf,
len as usize)))
}
Err(e) => return Ok(Some(Frame::Error(e))),
Err(e) => return Ok(Async::Ready(Frame::Error(e))),
}
}
}
@@ -162,18 +135,18 @@ impl ReadState {
NextReadAction::Stop(result) => {
match result {
Ok(buf) => NextReadState::Reset(buf),
Err(e) => return Ok(Some(Frame::Error(e))),
Err(e) => return Ok(Async::Ready(Frame::Error(e))),
}
}
}
}
};
match next {
NextReadState::Same => return Ok(None),
NextReadState::Same => return Ok(Async::NotReady),
NextReadState::Next(next) => *self = next,
NextReadState::Reset(packet) => {
*self = ReadState::init();
return Ok(Some(Frame::Message(packet)));
return Ok(Async::Ready(Frame::Message(packet)));
}
}
}

View File

@@ -7,38 +7,12 @@ use bincode::SizeLimit;
use bincode::serde as bincode;
use byteorder::{BigEndian, WriteBytesExt};
use bytes::Buf;
use futures::Async;
use serde::Serialize;
use std::collections::VecDeque;
use std::mem;
use std::io::{self, Cursor};
mod try_write {
use bytes::Buf;
use protocol::MapNonBlock;
use std::io::{self, Write};
pub trait TryWrite {
fn try_write_buf<B: Buf>(&mut self, buf: &mut B) -> io::Result<Option<usize>>
where Self: Sized
{
let res = self.try_write(buf.bytes());
if let Ok(Some(cnt)) = res {
buf.advance(cnt);
}
res
}
fn try_write(&mut self, buf: &[u8]) -> io::Result<Option<usize>>;
}
impl<T: Write> TryWrite for T {
fn try_write(&mut self, src: &[u8]) -> io::Result<Option<usize>> {
self.write(src).map_non_block()
}
}
}
use std::mem;
use tokio_proto::TryWrite;
/// The means of communication between client and server.
#[derive(Clone, Debug)]
@@ -74,7 +48,7 @@ enum NextWriteAction {
trait BufExt: Buf + Sized {
/// Writes data to stream. Returns Ok(true) if all data has been written or Ok(false) if
/// there's still data to write.
fn try_write<W: try_write::TryWrite>(&mut self, stream: &mut W) -> io::Result<NextWriteAction> {
fn try_write<W: TryWrite>(&mut self, stream: &mut W) -> io::Result<NextWriteAction> {
while let Some(bytes_written) = stream.try_write_buf(self)? {
debug!("Writer: wrote {} bytes; {} remaining.",
bytes_written,
@@ -100,10 +74,10 @@ pub enum NextWriteState {
}
impl NextWriteState {
pub fn next<W: try_write::TryWrite>(state: &mut Option<Packet>,
pub fn next<W: TryWrite>(state: &mut Option<Packet>,
socket: &mut W,
outbound: &mut VecDeque<Packet>)
-> io::Result<Option<()>> {
-> io::Result<Async<()>> {
loop {
let update = match *state {
None => {
@@ -113,13 +87,13 @@ impl NextWriteState {
debug_assert!(size >= mem::size_of::<u64>() as u64);
NextWriteState::Next(packet)
}
None => return Ok(Some(())),
None => return Ok(Async::Ready(())),
}
}
Some(ref mut packet) => {
match packet.buf.try_write(socket)? {
match BufExt::try_write(&mut packet.buf, socket)? {
NextWriteAction::Stop => NextWriteState::Nothing,
NextWriteAction::Continue => return Ok(None),
NextWriteAction::Continue => return Ok(Async::NotReady),
}
}
};

View File

@@ -4,7 +4,7 @@
// This file may not be copied, modified, or distributed except according to those terms.
use errors::{SerializableError, WireError};
use futures::{self, Future};
use futures::{self, Async, Future};
use futures::stream::Empty;
use futures_cpupool::{CpuFuture, CpuPool};
use protocol::{LOOP_HANDLE, TarpcTransport};
@@ -13,28 +13,44 @@ use serde::Serialize;
use std::io;
use std::net::ToSocketAddrs;
use tokio_proto::pipeline;
use tokio_proto::NewService;
use tokio_proto::server::{self, ServerHandle};
use tokio_service::NewService;
use util::Never;
/// Start a Tarpc service listening on the given address.
pub fn listen<A, T>(addr: A, new_service: T) -> io::Result<ServerHandle>
where T: NewService<Req = Vec<u8>,
Resp = pipeline::Message<Packet, Empty<(), io::Error>>,
/// Spawns a service that binds to the given address and runs on the default tokio `Loop`.
pub fn listen<A, T>(addr: A, new_service: T) -> ListenFuture
where T: NewService<Request = Vec<u8>,
Response = pipeline::Message<Packet, Empty<Never, io::Error>>,
Error = io::Error> + Send + 'static,
A: ToSocketAddrs
{
let mut addrs = addr.to_socket_addrs()?;
let addr = if let Some(a) = addrs.next() {
a
} else {
return Err(io::Error::new(io::ErrorKind::AddrNotAvailable,
"`ToSocketAddrs::to_socket_addrs` returned an empty iterator."));
};
// TODO(tikue): don't use ToSocketAddrs, or don't unwrap.
let addr = addr.to_socket_addrs().unwrap().next().unwrap();
server::listen(LOOP_HANDLE.clone(), addr, move |stream| {
pipeline::Server::new(new_service.new_service()?, TarpcTransport::new(stream))
})
.wait()
let (tx, rx) = futures::oneshot();
LOOP_HANDLE.spawn(move |handle| {
Ok(tx.complete(server::listen(handle, addr, move |stream| {
pipeline::Server::new(new_service.new_service()?, TarpcTransport::new(stream))
}).unwrap()))
});
ListenFuture { inner: rx }
}
/// A future that resolves to a `ServerHandle`.
pub struct ListenFuture {
inner: futures::Oneshot<ServerHandle>,
}
impl Future for ListenFuture {
type Item = ServerHandle;
type Error = Never;
fn poll(&mut self) -> futures::Poll<Self::Item, Self::Error> {
match self.inner.poll().unwrap() {
Async::Ready(server_handle) => Ok(Async::Ready(server_handle)),
Async::NotReady => Ok(Async::NotReady),
}
}
}
/// Returns a future containing the serialized reply.
@@ -48,23 +64,22 @@ pub fn serialize_reply<T: Serialize + Send + 'static,
-> SerializeFuture
{
POOL.spawn(futures::lazy(move || {
let packet = match Packet::serialize(&result) {
Ok(packet) => packet,
Err(e) => {
let err: Result<T, WireError<E>> =
Err(WireError::ServerSerialize(e.to_string()));
Packet::serialize(&err).unwrap()
}
};
futures::finished(pipeline::Message::WithoutBody(packet))
}))
let packet = match Packet::serialize(&result) {
Ok(packet) => packet,
Err(e) => {
let err: Result<T, WireError<E>> = Err(WireError::ServerSerialize(e.to_string()));
Packet::serialize(&err).unwrap()
}
};
futures::finished(pipeline::Message::WithoutBody(packet))
}))
}
#[doc(hidden)]
pub type SerializeFuture = CpuFuture<SerializedReply, io::Error>;
#[doc(hidden)]
pub type SerializedReply = pipeline::Message<Packet, Empty<(), io::Error>>;
pub type SerializedReply = pipeline::Message<Packet, Empty<Never, io::Error>>;
lazy_static! {
static ref POOL: CpuPool = { CpuPool::new_num_cpus() };