diff --git a/Cargo.toml b/Cargo.toml index 9dfd391..1917fb5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,5 +4,5 @@ members = [ "tonic-macros", "tonic-build", "tonic-examples", - "tonic-interop", + # "tonic-interop", ] diff --git a/tonic-examples/Cargo.toml b/tonic-examples/Cargo.toml index d8617d7..1d3353d 100644 --- a/tonic-examples/Cargo.toml +++ b/tonic-examples/Cargo.toml @@ -14,9 +14,9 @@ path = "src/helloworld/server.rs" name = "helloworld-client" path = "src/helloworld/client.rs" -[[bin]] -name = "routeguide-server" -path = "src/routeguide/server.rs" +# [[bin]] +# name = "routeguide-server" +# path = "src/routeguide/server.rs" [[bin]] name = "routeguide-client" diff --git a/tonic-examples/src/helloworld/server.rs b/tonic-examples/src/helloworld/server.rs index b5b5a1b..043e85a 100644 --- a/tonic-examples/src/helloworld/server.rs +++ b/tonic-examples/src/helloworld/server.rs @@ -1,8 +1,8 @@ -use tonic::transport::Server; -use tonic::{Request, Response, Status}; +use tonic::{Request, Response, Status, Server}; pub mod hello_world { include!(concat!(env!("OUT_DIR"), "/helloworld.rs")); + tonic::server!(service = "helloworld.Greeter", proto = "self"); } #[derive(Default, Clone)] @@ -10,12 +10,9 @@ pub struct MyGreeter { data: String, } -#[tonic::server(service = "helloworld.Greeter", proto = "hello_world")] -impl MyGreeter { - pub async fn say_hello( - &self, - request: Request, - ) -> Result, Status> { +#[tonic::server_trait] +impl hello_world::Greeter for MyGreeter { + async fn say_hello(self, request: Request) -> Result, Status> { println!("Got a request: {:?}", request); let string = &self.data; @@ -35,7 +32,7 @@ async fn main() -> Result<(), Box> { let greeter = MyGreeter::default(); Server::builder() - .serve(addr, GreeterServer::new(greeter)) + .serve(addr, hello_world::GreeterServer::new(greeter)) .await?; Ok(()) diff --git a/tonic-macros/src/lib.rs b/tonic-macros/src/lib.rs index 47dd335..255d8f5 100644 --- a/tonic-macros/src/lib.rs +++ b/tonic-macros/src/lib.rs @@ -57,19 +57,15 @@ pub fn client(attr: TokenStream) -> TokenStream { TokenStream::from(output) } -#[proc_macro_attribute] -pub fn server(attr: TokenStream, item: TokenStream) -> TokenStream { - let mut original = item.clone(); - let item = syn::parse_macro_input!(item as ItemImpl); +#[proc_macro] +pub fn server(attr: TokenStream) -> TokenStream { let args = syn::parse_macro_input!(attr as AttributeArgs); let (service, proto_path) = load_service(args); - let service_def = service::parse_service_impl(item, service, proto_path); - let output = service::generate(service_def); + let output = service::generate(service, &proto_path); - original.extend(TokenStream::from(output)); - original + TokenStream::from(output) } fn load_service(attr: AttributeArgs) -> (Service, String) { diff --git a/tonic-macros/src/service.rs b/tonic-macros/src/service.rs index 1fb9ede..3304db5 100644 --- a/tonic-macros/src/service.rs +++ b/tonic-macros/src/service.rs @@ -1,99 +1,49 @@ use crate::{Method, Service}; use proc_macro2::{Span, TokenStream}; use quote::quote; -use syn::{Ident, ImplItem, ImplItemMethod, ItemImpl, Lit, LitStr, Path, Type}; +use syn::{Ident, Lit, LitStr, Path}; -#[derive(Debug)] -pub struct ServiceDef { - name: Path, - name_str: String, - package: String, - proto_name: String, - proto_path: String, - methods: Vec<(Method, Ident)>, -} +pub(crate) fn generate(service: Service, proto_path: &str) -> TokenStream { + let methods = generate_methods(&service, proto_path); -pub(crate) fn parse_service_impl( - item: ItemImpl, - mut service: Service, - proto_path: String, -) -> ServiceDef { - let ItemImpl { self_ty, items, .. } = item; - - let name = if let Type::Path(t) = *self_ty { - t.path.clone() - } else { - panic!("wrong type!") - }; - - let mut methods = Vec::new(); - - for item in items { - if let ImplItem::Method(method) = item { - let ImplItemMethod { sig, .. } = method; - - if sig.asyncness.is_some() { - let name = format!("{}", sig.ident); - - if let Some((i, _)) = service - .methods - .iter() - .enumerate() - .find(|(_, method)| method.name == name) - { - let method = service.methods.remove(i); - methods.push((method, sig.ident)); - } - } - } - } - - ServiceDef { - name, - name_str: service.name, - package: service.package, - proto_name: service.proto_name, - proto_path, - methods, - } -} - -pub(crate) fn generate(service: ServiceDef) -> TokenStream { - let service_impl = service.name.clone(); - let methods = generate_methods(&service); - - let server_make_service = quote::format_ident!("{}Server", service.name_str); - let server_service = quote::format_ident!("{}ServerSvc", service.name_str); + let server_make_service = quote::format_ident!("{}Server", service.name); + let server_service = quote::format_ident!("{}ServerSvc", service.name); + let server_trait = quote::format_ident!("{}", service.name); quote! { use tonic::_codegen::*; + #[async_trait] + pub trait #server_trait : Clone + Send + 'static { + async fn say_hello(self, req: tonic::Request) + -> Result, tonic::Status>; + } + // TODO: impl debug #[derive(Clone)] - pub struct #server_make_service { - inner: std::sync::Arc<#service_impl>, + pub struct #server_make_service { + inner: T, } // TODO: impl debug - pub struct #server_service { - inner: std::sync::Arc<#service_impl>, + pub struct #server_service { + inner: T, } - impl #server_make_service { - pub fn new(t: #service_impl) -> Self { - let inner = std::sync::Arc::new(t); + impl #server_make_service { + pub fn new(inner: T) -> Self { Self { inner } } } - impl #server_service { - pub fn new(inner: std::sync::Arc<#service_impl>) -> Self { + impl #server_service { + pub fn new(inner: T) -> Self { Self { inner } } } - impl Service for #server_make_service { - type Response = #server_service; + impl Service for #server_make_service { + type Response = #server_service ; type Error = tonic::error::Never; type Future = Ready>; @@ -101,12 +51,12 @@ pub(crate) fn generate(service: ServiceDef) -> TokenStream { Poll::Ready(Ok(())) } - fn call(&mut self, _: T) -> Self::Future { + fn call(&mut self, _: R) -> Self::Future { ok(#server_service ::new(self.inner.clone())) } } - impl Service> for #server_service { + impl Service> for #server_service { type Response = http::Response; type Error = tonic::error::Never; type Future = BoxFuture; @@ -128,44 +78,48 @@ pub(crate) fn generate(service: ServiceDef) -> TokenStream { } } -fn generate_methods(service: &ServiceDef) -> TokenStream { +fn generate_methods(service: &Service, proto_path: &str) -> TokenStream { let mut stream = TokenStream::new(); - for (method, ident) in &service.methods { + for method in &service.methods { let path = format!( "/{}.{}/{}", service.package, service.proto_name, method.proto_name ); let method_path = Lit::Str(LitStr::new(&path, Span::call_site())); + let ident = quote::format_ident!("{}", method.name); + let server_trait = quote::format_ident!("{}", service.name); let method_stream = match (method.client_streaming, method.server_streaming) { (false, false) => generate_unary( method, - ident.clone(), - service.name.clone(), - &service.proto_path, + ident, + proto_path, + server_trait ), - (false, true) => generate_server_streaming( - method, - ident.clone(), - service.name.clone(), - &service.proto_path, - ), + _ => unimplemented!() - (true, false) => generate_client_streaming( - method, - ident.clone(), - service.name.clone(), - &service.proto_path, - ), + // (false, true) => generate_server_streaming( + // method, + // ident.clone(), + // service.name.clone(), + // &service.proto_path, + // ), - (true, true) => generate_streaming( - method, - ident.clone(), - service.name.clone(), - &service.proto_path, - ), + // (true, false) => generate_client_streaming( + // method, + // ident.clone(), + // service.name.clone(), + // &service.proto_path, + // ), + + // (true, true) => generate_streaming( + // method, + // ident.clone(), + // service.name.clone(), + // &service.proto_path, + // ), }; let method = quote! { @@ -182,8 +136,8 @@ fn generate_methods(service: &ServiceDef) -> TokenStream { fn generate_unary( method: &Method, method_ident: Ident, - service_impl: Path, proto_path: &str, + server_trait: Ident, ) -> TokenStream { let service_ident = Ident::new(&method.proto_name, Span::call_site()); @@ -192,9 +146,9 @@ fn generate_unary( syn::parse_str(&format!("{}::{}", proto_path, method.output_type)).unwrap(); quote! { - struct #service_ident(pub std::sync::Arc<#service_impl>); + struct #service_ident (pub T); - impl tonic::server::UnaryService<#request> for #service_ident { + impl tonic::server::UnaryService<#request> for #service_ident { type Response = #response; type Future = BoxFuture, tonic::Status>; @@ -221,141 +175,141 @@ fn generate_unary( } } -fn generate_server_streaming( - method: &Method, - method_ident: Ident, - service_impl: Path, - proto_path: &str, -) -> TokenStream { - let service_ident = Ident::new(&method.proto_name, Span::call_site()); +// fn generate_server_streaming( +// method: &Method, +// method_ident: Ident, +// service_impl: Path, +// proto_path: &str, +// ) -> 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: Path = syn::parse_str(&format!("{}::{}", proto_path, method.input_type)).unwrap(); +// let response: Path = +// syn::parse_str(&format!("{}::{}", proto_path, method.output_type)).unwrap(); - // TODO: parse response stream type, if it is a concrete type then use that - // as the ResponseStream type, if it is a impl Trait then we need to box. - quote! { - struct #service_ident(pub std::sync::Arc<#service_impl>); +// // TODO: parse response stream type, if it is a concrete type then use that +// // as the ResponseStream type, if it is a impl Trait then we need to box. +// quote! { +// struct #service_ident(pub std::sync::Arc<#service_impl>); - impl tonic::server::ServerStreamingService<#request> for #service_ident { - type Response = #response; - type ResponseStream = Pin> + Send>>; - type Future = BoxFuture, tonic::Status>; +// impl tonic::server::ServerStreamingService<#request> for #service_ident { +// type Response = #response; +// type ResponseStream = Pin> + Send>>; +// type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request<#request>) -> Self::Future { - let inner = self.0.clone(); - let fut = async move { - inner.#method_ident(request) - .await - .map(|r| - r.map(|s| Box::pin(s) as Pin> + Send>>)) +// fn call(&mut self, request: tonic::Request<#request>) -> Self::Future { +// let inner = self.0.clone(); +// let fut = async move { +// inner.#method_ident(request) +// .await +// .map(|r| +// r.map(|s| Box::pin(s) as Pin> + Send>>)) - }; - Box::pin(fut) - } - } +// }; +// Box::pin(fut) +// } +// } - let inner = self.inner.clone(); - let fut = async move { - let method = #service_ident(inner); - let codec = tonic::codec::ProstCodec::new(); - let mut grpc = tonic::server::Grpc::new(codec); - let res = grpc.server_streaming(method, req).await; - Ok(res) - }; +// let inner = self.inner.clone(); +// let fut = async move { +// let method = #service_ident(inner); +// let codec = tonic::codec::ProstCodec::new(); +// let mut grpc = tonic::server::Grpc::new(codec); +// let res = grpc.server_streaming(method, req).await; +// Ok(res) +// }; - Box::pin(fut) - } -} +// Box::pin(fut) +// } +// } -fn generate_client_streaming( - method: &Method, - method_ident: Ident, - service_impl: Path, - proto_path: &str, -) -> TokenStream { - let service_ident = Ident::new(&method.proto_name, Span::call_site()); +// fn generate_client_streaming( +// method: &Method, +// method_ident: Ident, +// service_impl: Path, +// proto_path: &str, +// ) -> 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: Path = syn::parse_str(&format!("{}::{}", proto_path, method.input_type)).unwrap(); +// let response: Path = +// syn::parse_str(&format!("{}::{}", proto_path, method.output_type)).unwrap(); - quote! { - struct #service_ident(pub std::sync::Arc<#service_impl>); +// quote! { +// struct #service_ident(pub std::sync::Arc<#service_impl>); - impl tonic::server::ClientStreamingService for #service_ident - where S: tonic::_codegen::Stream> + Unpin + Send + 'static { - type Response = #response; - type Future = BoxFuture, tonic::Status>; +// impl tonic::server::ClientStreamingService for #service_ident +// where S: tonic::_codegen::Stream> + Unpin + Send + 'static { +// type Response = #response; +// type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { - let inner = self.0.clone(); - let fut = async move { - inner.#method_ident(request).await +// fn call(&mut self, request: tonic::Request) -> Self::Future { +// let inner = self.0.clone(); +// let fut = async move { +// inner.#method_ident(request).await - }; - Box::pin(fut) - } - } +// }; +// Box::pin(fut) +// } +// } - let inner = self.inner.clone(); - let fut = async move { - let method = #service_ident(inner); - let codec = tonic::codec::ProstCodec::new(); - let mut grpc = tonic::server::Grpc::new(codec); - let res = grpc.client_streaming(method, req).await; - Ok(res) - }; +// let inner = self.inner.clone(); +// let fut = async move { +// let method = #service_ident(inner); +// let codec = tonic::codec::ProstCodec::new(); +// let mut grpc = tonic::server::Grpc::new(codec); +// let res = grpc.client_streaming(method, req).await; +// Ok(res) +// }; - Box::pin(fut) - } -} +// Box::pin(fut) +// } +// } -fn generate_streaming( - method: &Method, - method_ident: Ident, - service_impl: Path, - proto_path: &str, -) -> TokenStream { - let service_ident = Ident::new(&method.proto_name, Span::call_site()); +// fn generate_streaming( +// method: &Method, +// method_ident: Ident, +// service_impl: Path, +// proto_path: &str, +// ) -> 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: Path = syn::parse_str(&format!("{}::{}", proto_path, method.input_type)).unwrap(); +// let response: Path = +// syn::parse_str(&format!("{}::{}", proto_path, method.output_type)).unwrap(); - // TODO: parse response stream type, if it is a concrete type then use that - // as the ResponseStream type, if it is a impl Trait then we need to box. - quote! { - struct #service_ident(pub std::sync::Arc<#service_impl>); +// // TODO: parse response stream type, if it is a concrete type then use that +// // as the ResponseStream type, if it is a impl Trait then we need to box. +// quote! { +// struct #service_ident(pub std::sync::Arc<#service_impl>); - impl tonic::server::StreamingService for #service_ident - where S: Stream> + Unpin + Send + 'static { - type Response = #response; - type ResponseStream = Pin> + Send>>; - type Future = BoxFuture, tonic::Status>; +// impl tonic::server::StreamingService for #service_ident +// where S: Stream> + Unpin + Send + 'static { +// type Response = #response; +// type ResponseStream = Pin> + Send>>; +// type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { - let inner = self.0.clone(); - let fut = async move { - inner.#method_ident(request).await - .map(|r| - r.map(|s| Box::pin(s) as Pin> + Send>>)) +// fn call(&mut self, request: tonic::Request) -> Self::Future { +// let inner = self.0.clone(); +// let fut = async move { +// inner.#method_ident(request).await +// .map(|r| +// r.map(|s| Box::pin(s) as Pin> + Send>>)) - }; - Box::pin(fut) - } - } +// }; +// Box::pin(fut) +// } +// } - let inner = self.inner.clone(); - let fut = async move { - let method = #service_ident(inner); - let codec = tonic::codec::ProstCodec::new(); - let mut grpc = tonic::server::Grpc::new(codec); - let res = grpc.streaming(method, req).await; - Ok(res) - }; +// let inner = self.inner.clone(); +// let fut = async move { +// let method = #service_ident(inner); +// let codec = tonic::codec::ProstCodec::new(); +// let mut grpc = tonic::server::Grpc::new(codec); +// let res = grpc.streaming(method, req).await; +// Ok(res) +// }; - Box::pin(fut) - } -} +// Box::pin(fut) +// } +// } diff --git a/tonic/Cargo.toml b/tonic/Cargo.toml index b8d0116..3ac0168 100644 --- a/tonic/Cargo.toml +++ b/tonic/Cargo.toml @@ -19,6 +19,7 @@ tokio-codec = "=0.2.0-alpha.4" async-stream = { git = "https://github.com/tokio-rs/async-stream" } http-body = "0.2.0-alpha.1" pin-project = "=0.4.0-alpha.7" +async-trait = "0.1" # optional hyper = { version = "=0.13.0-alpha.1", optional = true } diff --git a/tonic/src/lib.rs b/tonic/src/lib.rs index 352c899..1552f7c 100644 --- a/tonic/src/lib.rs +++ b/tonic/src/lib.rs @@ -51,11 +51,17 @@ pub use request::Request; pub use response::Response; pub use status::{Code, Status}; pub use tonic_macros::{client, server}; +#[doc(inline)] +pub use transport::{Channel, Server}; pub(crate) use error::Error; +#[doc(hidden)] +pub use async_trait::async_trait as server_trait; + #[doc(hidden)] pub mod _codegen { + pub use async_trait::async_trait; pub use futures_core::Stream; pub use futures_util::future::{ok, poll_fn, Ready}; pub use http_body::Body as HttpBody;