diff --git a/tonic-build/Cargo.toml b/tonic-build/Cargo.toml index a5a85a5e2..d048c3473 100644 --- a/tonic-build/Cargo.toml +++ b/tonic-build/Cargo.toml @@ -3,6 +3,7 @@ name = "tonic-build" version = "0.1.0-alpha.1" authors = ["Lucio Franco "] edition = "2018" +license = "MIT" documentation = "https://docs.rs/tonic/0.1.0-alpha.1/tonic/" repository = "https://github.com/hyperium/tonic" homepage = "https://github.com/hyperium/tonic" diff --git a/tonic-build/src/client.rs b/tonic-build/src/client.rs index 9d9c044d3..63ef3254d 100644 --- a/tonic-build/src/client.rs +++ b/tonic-build/src/client.rs @@ -2,7 +2,6 @@ use crate::generate_doc_comments; use proc_macro2::TokenStream; use prost_build::{Method, Service}; use quote::{format_ident, quote}; -use syn::Path; pub(crate) fn generate(service: &Service, proto: &str) -> TokenStream { let service_ident = quote::format_ident!("{}Client", service.name); @@ -97,8 +96,8 @@ fn generate_methods(service: &Service, proto: &str) -> TokenStream { fn generate_unary(method: &Method, proto: &str, path: String) -> TokenStream { let ident = format_ident!("{}", method.name); - let request: Path = syn::parse_str(&format!("{}::{}", proto, method.input_type)).unwrap(); - let response: Path = syn::parse_str(&format!("{}::{}", proto, method.output_type)).unwrap(); + let request = crate::replace_wellknown(proto, &method.input_type); + let response = crate::replace_wellknown(proto, &method.output_type); quote! { pub async fn #ident(&mut self, request: tonic::Request<#request>) @@ -113,8 +112,9 @@ fn generate_unary(method: &Method, proto: &str, path: String) -> TokenStream { fn generate_server_streaming(method: &Method, proto: &str, path: String) -> TokenStream { let ident = format_ident!("{}", method.name); - let request: Path = syn::parse_str(&format!("{}::{}", proto, method.input_type)).unwrap(); - let response: Path = syn::parse_str(&format!("{}::{}", proto, method.output_type)).unwrap(); + + let request = crate::replace_wellknown(proto, &method.input_type); + let response = crate::replace_wellknown(proto, &method.output_type); quote! { pub async fn #ident(&mut self, request: tonic::Request<#request>) @@ -129,8 +129,9 @@ fn generate_server_streaming(method: &Method, proto: &str, path: String) -> Toke fn generate_client_streaming(method: &Method, proto: &str, path: String) -> TokenStream { let ident = format_ident!("{}", method.name); - let request: Path = syn::parse_str(&format!("{}::{}", proto, method.input_type)).unwrap(); - let response: Path = syn::parse_str(&format!("{}::{}", proto, method.output_type)).unwrap(); + + let request = crate::replace_wellknown(proto, &method.input_type); + let response = crate::replace_wellknown(proto, &method.output_type); quote! { pub async fn #ident(&mut self, request: tonic::Request) @@ -147,8 +148,9 @@ fn generate_client_streaming(method: &Method, proto: &str, path: String) -> Toke fn generate_streaming(method: &Method, proto: &str, path: String) -> TokenStream { let ident = format_ident!("{}", method.name); - let request: Path = syn::parse_str(&format!("{}::{}", proto, method.input_type)).unwrap(); - let response: Path = syn::parse_str(&format!("{}::{}", proto, method.output_type)).unwrap(); + + let request = crate::replace_wellknown(proto, &method.input_type); + let response = crate::replace_wellknown(proto, &method.output_type); quote! { pub async fn #ident(&mut self, request: tonic::Request) diff --git a/tonic-build/src/lib.rs b/tonic-build/src/lib.rs index 696c933d8..50def0ad8 100644 --- a/tonic-build/src/lib.rs +++ b/tonic-build/src/lib.rs @@ -59,7 +59,7 @@ use proc_macro2::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream}; use prost_build::Config; -use quote::TokenStreamExt; +use quote::{ToTokens, TokenStreamExt}; #[cfg(feature = "rustfmt")] use std::process::Command; @@ -77,6 +77,8 @@ pub struct Builder { build_client: bool, build_server: bool, out_dir: Option, + #[cfg(feature = "rustfmt")] + format: bool, } impl Builder { @@ -92,6 +94,13 @@ impl Builder { self } + /// Enable the output to be formated by rustfmt. + #[cfg(feature = "rustfmt")] + pub fn format(mut self, run: bool) -> Self { + self.format = run; + self + } + /// Set the output directory to generate code to. /// /// Defaults to the `OUT_DIR` environment variable. @@ -104,6 +113,9 @@ impl Builder { pub fn compile>(self, protos: &[P], includes: &[P]) -> io::Result<()> { let mut config = Config::new(); + #[cfg(feature = "rustfmt")] + let format = self.format; + let out_dir = self .out_dir .clone() @@ -114,7 +126,11 @@ impl Builder { config.compile_protos(protos, includes)?; #[cfg(feature = "rustfmt")] - fmt(out_dir.to_str().expect("Expected utf8 out_dir")); + { + if format { + fmt(out_dir.to_str().expect("Expected utf8 out_dir")); + } + } Ok(()) } @@ -128,6 +144,8 @@ pub fn configure() -> Builder { build_client: true, build_server: true, out_dir: None, + #[cfg(feature = "rustfmt")] + format: true, } } @@ -262,3 +280,14 @@ fn generate_doc_comments>(comments: &[T]) -> TokenStream { stream } + +fn replace_wellknown(proto_path: &str, output: &str) -> TokenStream { + // TODO: detect more wellknown protobuf types + // https://github.com/danburkert/prost/blob/master/prost-types/src/protobuf.rs + match output { + "()" => quote::quote! { () }, + _ => syn::parse_str::(&format!("{}::{}", proto_path, output)) + .unwrap() + .to_token_stream(), + } +} diff --git a/tonic-build/src/service.rs b/tonic-build/src/service.rs index 2b0e5b450..d18a64253 100644 --- a/tonic-build/src/service.rs +++ b/tonic-build/src/service.rs @@ -2,7 +2,7 @@ use crate::{generate_doc_comment, generate_doc_comments}; use proc_macro2::{Span, TokenStream}; use prost_build::{Method, Service}; use quote::quote; -use syn::{Ident, Lit, LitStr, Path}; +use syn::{Ident, Lit, LitStr}; pub(crate) fn generate(service: &Service, proto_path: &str) -> TokenStream { let methods = generate_methods(&service, proto_path); @@ -79,8 +79,13 @@ pub(crate) fn generate(service: &Service, proto_path: &str) -> TokenStream { match req.uri().path() { #methods - // TODO: implement grpc unimplemented for server - _ => unimplemented!(), + _ => Box::pin(async move { + Ok(http::Response::builder() + .status(200) + .header("grpc-status", "12") + .body(tonic::body::BoxBody::empty()) + .unwrap()) + }), } } } @@ -108,10 +113,9 @@ fn generate_trait_methods(service: &Service, proto_path: &str) -> TokenStream { for method in &service.methods { let name = quote::format_ident!("{}", method.name); - let req_message: Path = - syn::parse_str(&format!("{}::{}", proto_path, method.input_type)).unwrap(); - let res_message: Path = - syn::parse_str(&format!("{}::{}", proto_path, method.output_type)).unwrap(); + + let req_message = crate::replace_wellknown(proto_path, &method.input_type); + let res_message = crate::replace_wellknown(proto_path, &method.output_type); let method_doc = generate_doc_comments(&method.comments.leading); @@ -214,9 +218,8 @@ fn generate_unary( ) -> TokenStream { let service_ident = Ident::new(&method.proto_name, Span::call_site()); - let request: Path = syn::parse_str(&format!("{}::{}", proto_path, method.input_type)).unwrap(); - let response: Path = - syn::parse_str(&format!("{}::{}", proto_path, method.output_type)).unwrap(); + let request = crate::replace_wellknown(proto_path, &method.input_type); + let response = crate::replace_wellknown(proto_path, &method.output_type); quote! { struct #service_ident(pub Arc); @@ -255,9 +258,8 @@ fn generate_server_streaming( ) -> TokenStream { let service_ident = Ident::new(&method.proto_name, Span::call_site()); - let request: Path = syn::parse_str(&format!("{}::{}", proto_path, method.input_type)).unwrap(); - let response: Path = - syn::parse_str(&format!("{}::{}", proto_path, method.output_type)).unwrap(); + let request = crate::replace_wellknown(proto_path, &method.input_type); + let response = crate::replace_wellknown(proto_path, &method.output_type); let response_stream = quote::format_ident!("{}Stream", method.proto_name); @@ -300,9 +302,8 @@ fn generate_client_streaming( ) -> TokenStream { let service_ident = Ident::new(&method.proto_name, Span::call_site()); - let request: Path = syn::parse_str(&format!("{}::{}", proto_path, method.input_type)).unwrap(); - let response: Path = - syn::parse_str(&format!("{}::{}", proto_path, method.output_type)).unwrap(); + let request = crate::replace_wellknown(proto_path, &method.input_type); + let response = crate::replace_wellknown(proto_path, &method.output_type); quote! { struct #service_ident(pub Arc); @@ -343,9 +344,8 @@ fn generate_streaming( ) -> TokenStream { let service_ident = Ident::new(&method.proto_name, Span::call_site()); - let request: Path = syn::parse_str(&format!("{}::{}", proto_path, method.input_type)).unwrap(); - let response: Path = - syn::parse_str(&format!("{}::{}", proto_path, method.output_type)).unwrap(); + let request = crate::replace_wellknown(proto_path, &method.input_type); + let response = crate::replace_wellknown(proto_path, &method.output_type); let response_stream = quote::format_ident!("{}Stream", method.proto_name); diff --git a/tonic-build/tests/empty.rs b/tonic-build/tests/empty.rs new file mode 100644 index 000000000..5e644cd2c --- /dev/null +++ b/tonic-build/tests/empty.rs @@ -0,0 +1,9 @@ +#[test] +fn empty() { + let tmp = std::env::temp_dir(); + tonic_build::configure() + .out_dir(tmp) + .format(false) + .compile(&["tests/protos/empty.proto"], &["tests/protos"]) + .unwrap(); +} diff --git a/tonic-build/tests/protos/empty.proto b/tonic-build/tests/protos/empty.proto new file mode 100644 index 000000000..0d5532ce0 --- /dev/null +++ b/tonic-build/tests/protos/empty.proto @@ -0,0 +1,7 @@ +syntax = "proto3"; +package empty; +import "google/protobuf/empty.proto"; + +service Admin { + rpc EmptyCall(google.protobuf.Empty) returns (google.protobuf.Empty); +}