Move generated functions under their corresponding items.

- fn serve -> Service::serve
- fn new_stub -> Client::new

This allows the generated function names to remain consistent across
service definitions while preventing collisions.
This commit is contained in:
Tim Kuehn
2019-07-30 20:13:32 -07:00
parent 2f24842b2d
commit 1b58914d59
12 changed files with 155 additions and 144 deletions

View File

@@ -135,6 +135,7 @@ pub fn service(attr: TokenStream, input: TokenStream) -> TokenStream {
ident,
rpcs,
} = parse_macro_input!(input as Service);
let vis_repeated = std::iter::repeat(vis.clone());
let camel_case_fn_names: Vec<String> = rpcs
.iter()
@@ -206,9 +207,7 @@ pub fn service(attr: TokenStream, input: TokenStream) -> TokenStream {
let response_fut_ident = Ident::new(&response_fut_name, ident.span());
let response_fut_ident_repeated = std::iter::repeat(response_fut_ident.clone());
let response_fut_ident_repeated2 = response_fut_ident_repeated.clone();
let snake_ident = camel_to_snake(&ident.to_string());
let serve_ident = Ident::new(&format!("serve_{}", snake_ident), ident.span());
let stub_ident = Ident::new(&format!("{}_stub", snake_ident), ident.span());
let server_ident = Ident::new(&format!("{}Server", ident), ident.span());
#[cfg(feature = "serde1")]
let derive_serialize = quote!(#[derive(serde::Serialize, serde::Deserialize)]);
@@ -219,6 +218,35 @@ pub fn service(attr: TokenStream, input: TokenStream) -> TokenStream {
#( #attrs )*
#vis trait #ident: Clone + Send + 'static {
#( #types_and_fns )*
/// Returns a serving function to use with tarpc::server::Server.
fn serve(self) -> #server_ident<Self> {
#server_ident { service: self }
}
}
#[derive(Clone)]
#vis struct #server_ident<S> {
service: S,
}
impl<S> tarpc::server::Serve<#request_ident> for #server_ident<S>
where S: #ident
{
type Resp = #response_ident;
type Fut = #response_fut_ident<S>;
fn serve(self, ctx: tarpc::context::Context, req: #request_ident) -> Self::Fut {
match req {
#(
#request_ident_repeated::#camel_case_idents{ #arg_vars } => {
#response_fut_ident_repeated2::#camel_case_idents2(
#service_name_repeated2::#method_names(
self.service, ctx, #arg_vars2))
}
)*
}
}
}
/// The request sent over the wire from the client to the server.
@@ -247,10 +275,10 @@ pub fn service(attr: TokenStream, input: TokenStream) -> TokenStream {
}
impl<S: #ident> std::future::Future for #response_fut_ident<S> {
type Output = std::io::Result<#response_ident>;
type Output = #response_ident;
fn poll(self: std::pin::Pin<&mut Self>, cx: &mut std::task::Context<'_>)
-> std::task::Poll<std::io::Result<#response_ident>>
-> std::task::Poll<#response_ident>
{
unsafe {
match std::pin::Pin::get_unchecked_mut(self) {
@@ -258,44 +286,18 @@ pub fn service(attr: TokenStream, input: TokenStream) -> TokenStream {
#response_fut_ident_repeated::#camel_case_idents(resp) =>
std::pin::Pin::new_unchecked(resp)
.poll(cx)
.map(#response_ident_repeated::#camel_case_idents2)
.map(Ok),
.map(#response_ident_repeated::#camel_case_idents2),
)*
}
}
}
}
/// Returns a serving function to use with tarpc::server::Server.
#vis fn #serve_ident<S: #ident>(service: S)
-> impl FnOnce(tarpc::context::Context, #request_ident) -> #response_fut_ident<S> + Send + 'static + Clone {
move |ctx, req| {
match req {
#(
#request_ident_repeated::#camel_case_idents{ #arg_vars } => {
#response_fut_ident_repeated2::#camel_case_idents2(
#service_name_repeated2::#method_names(
service.clone(), ctx, #arg_vars2))
}
)*
}
}
}
#[allow(unused)]
#[derive(Clone, Debug)]
/// The client stub that makes RPC calls to the server. Exposes a Future interface.
#vis struct #client_ident<C = tarpc::client::Channel<#request_ident, #response_ident>>(C);
/// Returns a new client stub that sends requests over the given transport.
#vis async fn #stub_ident<T>(config: tarpc::client::Config, transport: T)
-> std::io::Result<#client_ident>
where
T: tarpc::Transport<tarpc::ClientMessage<#request_ident>, tarpc::Response<#response_ident>> + Send + 'static,
{
Ok(#client_ident(tarpc::client::new(config, transport).await?))
}
impl<C> From<C> for #client_ident<C>
where for <'a> C: tarpc::Client<'a, #request_ident, Response = #response_ident>
{
@@ -304,13 +306,25 @@ pub fn service(attr: TokenStream, input: TokenStream) -> TokenStream {
}
}
impl #client_ident {
/// Returns a new client stub that sends requests over the given transport.
#vis async fn new<T>(config: tarpc::client::Config, transport: T)
-> std::io::Result<Self>
where
T: tarpc::Transport<tarpc::ClientMessage<#request_ident>, tarpc::Response<#response_ident>> + Send + 'static
{
Ok(#client_ident(tarpc::client::new(config, transport).await?))
}
}
impl<C> #client_ident<C>
where for<'a> C: tarpc::Client<'a, #request_ident, Response = #response_ident>
{
#(
#[allow(unused)]
#( #method_attrs )*
pub fn #method_names(&mut self, ctx: tarpc::context::Context, #args)
#vis_repeated fn #method_names(&mut self, ctx: tarpc::context::Context, #args)
-> impl std::future::Future<Output = std::io::Result<#outputs>> + '_ {
let request = #request_ident_repeated2::#camel_case_idents { #arg_vars };
let resp = tarpc::Client::call(&mut self.0, ctx, request);
@@ -347,28 +361,6 @@ fn snake_to_camel(ident_str: &str) -> String {
camel_ty
}
// Really basic camel to snake that assumes capitals are always the start of a new segment.
fn camel_to_snake(ident_str: &str) -> String {
let mut snake = String::new();
let mut chars = ident_str.chars();
if let Some(c) = chars.next() {
snake.extend(c.to_lowercase());
}
while let Some(c) = chars.next() {
if c.is_uppercase() {
// New word
snake.push('_');
snake.extend(c.to_lowercase());
} else {
// Same word
snake.push(c)
}
}
snake
}
#[test]
fn snake_to_camel_basic() {
assert_eq!(snake_to_camel("abc_def"), "AbcDef");
@@ -393,8 +385,3 @@ fn snake_to_camel_underscore_consecutive() {
fn snake_to_camel_capital_in_middle() {
assert_eq!(snake_to_camel("aBc_dEf"), "AbcDef");
}
#[test]
fn camel_to_snake_basic() {
assert_eq!(camel_to_snake("AbcDef"), "abc_def");
}