diff --git a/Cargo.toml b/Cargo.toml index 1917fb5..7687b5d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,6 @@ [workspace] members = [ "tonic", - "tonic-macros", "tonic-build", "tonic-examples", # "tonic-interop", diff --git a/out/helloworld.rs b/out/helloworld.rs new file mode 100644 index 0000000..7beae83 --- /dev/null +++ b/out/helloworld.rs @@ -0,0 +1,128 @@ +/// The request message containing the user's name. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct HelloRequest { + #[prost(string, tag = "1")] + pub name: std::string::String, +} +/// The response message containing the greetings +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct HelloReply { + #[prost(string, tag = "1")] + pub message: std::string::String, +} +use tonic::_codegen::*; +#[async_trait] +pub trait Greeter: Send + Sync + 'static { + async fn say_hello( + &self, + request: tonic::Request, + ) -> Result, tonic::Status>; +} +#[derive(Clone)] +pub struct GreeterServer { + inner: std::sync::Arc, +} +pub struct GreeterServerSvc { + inner: std::sync::Arc, +} +impl GreeterServer { + pub fn new(inner: T) -> Self { + let inner = std::sync::Arc::new(inner); + Self { inner } + } +} +impl GreeterServerSvc { + pub fn new(inner: std::sync::Arc) -> Self { + Self { inner } + } +} +impl Service for GreeterServer { + type Response = GreeterServerSvc; + type Error = tonic::error::Never; + type Future = Ready>; + fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll> { + Poll::Ready(Ok(())) + } + fn call(&mut self, _: R) -> Self::Future { + ok(GreeterServerSvc::new(self.inner.clone())) + } +} +impl Service> for GreeterServerSvc { + type Response = http::Response; + type Error = tonic::error::Never; + type Future = BoxFuture; + fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll> { + Poll::Ready(Ok(())) + } + fn call(&mut self, req: http::Request) -> Self::Future { + let inner = self.inner.clone(); + match req.uri().path() { + "/helloworld.Greeter/SayHello" => { + struct SayHello(pub std::sync::Arc); + impl tonic::server::UnaryService for SayHello { + type Response = self::HelloReply; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { inner.say_hello(request).await }; + Box::pin(fut) + } + } + let inner = self.inner.clone(); + let fut = async move { + let method = SayHello(inner); + let codec = tonic::codec::ProstCodec::new(); + let mut grpc = tonic::server::Grpc::new(codec); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + _ => unimplemented!("use grpc unimplemented"), + } + } +} +use tonic::_codegen::*; +pub struct GreeterClient { + inner: tonic::client::Grpc, +} +impl GreeterClient +where + T: tonic::client::GrpcService, + T::ResponseBody: tonic::body::Body + tonic::_codegen::HttpBody + Send + 'static, + T::Error: Into, + ::Error: Into + Send, + ::Data: Into + Send, +{ + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub async fn ready(&mut self) -> Result<(), tonic::Status> { + self.inner.ready().await.map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + }) + } + pub async fn say_hello( + &mut self, + request: tonic::Request, + ) -> Result, tonic::Status> { + self.ready().await?; + let codec = tonic::codec::ProstCodec::new(); + let path = http::uri::PathAndQuery::from_static("/helloworld.Greeter/SayHello"); + self.inner.unary(request, path, codec).await + } +} +impl Clone for GreeterClient { + fn clone(&self) -> Self { + Self { + inner: self.inner.clone(), + } + } +} diff --git a/out/routeguide.rs b/out/routeguide.rs new file mode 100644 index 0000000..e7f150a --- /dev/null +++ b/out/routeguide.rs @@ -0,0 +1,303 @@ +/// Points are represented as latitude-longitude pairs in the E7 representation +/// (degrees multiplied by 10**7 and rounded to the nearest integer). +/// Latitudes should be in the range +/- 90 degrees and longitude should be in +/// the range +/- 180 degrees (inclusive). +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Point { + #[prost(int32, tag = "1")] + pub latitude: i32, + #[prost(int32, tag = "2")] + pub longitude: i32, +} +/// A latitude-longitude rectangle, represented as two diagonally opposite +/// points "lo" and "hi". +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Rectangle { + /// One corner of the rectangle. + #[prost(message, optional, tag = "1")] + pub lo: ::std::option::Option, + /// The other corner of the rectangle. + #[prost(message, optional, tag = "2")] + pub hi: ::std::option::Option, +} +/// A feature names something at a given point. +/// +/// If a feature could not be named, the name is empty. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Feature { + /// The name of the feature. + #[prost(string, tag = "1")] + pub name: std::string::String, + /// The point where the feature is detected. + #[prost(message, optional, tag = "2")] + pub location: ::std::option::Option, +} +/// A RouteNote is a message sent while at a given point. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct RouteNote { + /// The location from which the message is sent. + #[prost(message, optional, tag = "1")] + pub location: ::std::option::Option, + /// The message to be sent. + #[prost(string, tag = "2")] + pub message: std::string::String, +} +/// A RouteSummary is received in response to a RecordRoute rpc. +/// +/// It contains the number of individual points received, the number of +/// detected features, and the total distance covered as the cumulative sum of +/// the distance between each point. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct RouteSummary { + /// The number of points received. + #[prost(int32, tag = "1")] + pub point_count: i32, + /// The number of known features passed while traversing the route. + #[prost(int32, tag = "2")] + pub feature_count: i32, + /// The distance covered in metres. + #[prost(int32, tag = "3")] + pub distance: i32, + /// The duration of the traversal in seconds. + #[prost(int32, tag = "4")] + pub elapsed_time: i32, +} +use tonic::_codegen::*; +#[async_trait] +pub trait RouteGuide: Send + Sync + 'static { + async fn get_feature( + &self, + request: tonic::Request, + ) -> Result, tonic::Status>; + type ListFeaturesStream: Stream> + + Unpin + + Send + + 'static; + async fn list_features( + &self, + request: tonic::Request, + ) -> Result, tonic::Status>; + async fn record_route( + &self, + request: tonic::Request>, + ) -> Result, tonic::Status>; + type RouteChatStream: Stream> + + Unpin + + Send + + 'static; + async fn route_chat( + &self, + request: tonic::Request>, + ) -> Result, tonic::Status>; +} +#[derive(Clone)] +pub struct RouteGuideServer { + inner: std::sync::Arc, +} +pub struct RouteGuideServerSvc { + inner: std::sync::Arc, +} +impl RouteGuideServer { + pub fn new(inner: T) -> Self { + let inner = std::sync::Arc::new(inner); + Self { inner } + } +} +impl RouteGuideServerSvc { + pub fn new(inner: std::sync::Arc) -> Self { + Self { inner } + } +} +impl Service for RouteGuideServer { + type Response = RouteGuideServerSvc; + type Error = tonic::error::Never; + type Future = Ready>; + fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll> { + Poll::Ready(Ok(())) + } + fn call(&mut self, _: R) -> Self::Future { + ok(RouteGuideServerSvc::new(self.inner.clone())) + } +} +impl Service> for RouteGuideServerSvc { + type Response = http::Response; + type Error = tonic::error::Never; + type Future = BoxFuture; + fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll> { + Poll::Ready(Ok(())) + } + fn call(&mut self, req: http::Request) -> Self::Future { + let inner = self.inner.clone(); + match req.uri().path() { + "/routeguide.RouteGuide/GetFeature" => { + struct GetFeature(pub std::sync::Arc); + impl tonic::server::UnaryService for GetFeature { + type Response = self::Feature; + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { inner.get_feature(request).await }; + Box::pin(fut) + } + } + let inner = self.inner.clone(); + let fut = async move { + let method = GetFeature(inner); + let codec = tonic::codec::ProstCodec::new(); + let mut grpc = tonic::server::Grpc::new(codec); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/routeguide.RouteGuide/ListFeatures" => { + struct ListFeatures(pub std::sync::Arc); + impl tonic::server::ServerStreamingService for ListFeatures { + type Response = self::Feature; + type ResponseStream = T::ListFeaturesStream; + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { inner.list_features(request).await }; + Box::pin(fut) + } + } + let inner = self.inner.clone(); + let fut = async move { + let method = ListFeatures(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) + } + "/routeguide.RouteGuide/RecordRoute" => { + struct RecordRoute(pub std::sync::Arc); + impl tonic::server::ClientStreamingService for RecordRoute { + type Response = self::RouteSummary; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, + request: tonic::Request>, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { inner.record_route(request).await }; + Box::pin(fut) + } + } + let inner = self.inner.clone(); + let fut = async move { + let method = RecordRoute(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) + } + "/routeguide.RouteGuide/RouteChat" => { + struct RouteChat(pub std::sync::Arc); + impl tonic::server::StreamingService for RouteChat { + type Response = self::RouteNote; + type ResponseStream = T::RouteChatStream; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, + request: tonic::Request>, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { inner.route_chat(request).await }; + Box::pin(fut) + } + } + let inner = self.inner.clone(); + let fut = async move { + let method = RouteChat(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) + } + _ => unimplemented!("use grpc unimplemented"), + } + } +} +use tonic::_codegen::*; +pub struct RouteGuideClient { + inner: tonic::client::Grpc, +} +impl RouteGuideClient +where + T: tonic::client::GrpcService, + T::ResponseBody: tonic::body::Body + tonic::_codegen::HttpBody + Send + 'static, + T::Error: Into, + ::Error: Into + Send, + ::Data: Into + Send, +{ + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub async fn ready(&mut self) -> Result<(), tonic::Status> { + self.inner.ready().await.map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + }) + } + pub async fn get_feature( + &mut self, + request: tonic::Request, + ) -> Result, tonic::Status> { + self.ready().await?; + let codec = tonic::codec::ProstCodec::new(); + let path = http::uri::PathAndQuery::from_static("/routeguide.RouteGuide/GetFeature"); + self.inner.unary(request, path, codec).await + } + pub async fn list_features( + &mut self, + request: tonic::Request, + ) -> Result>, tonic::Status> { + self.ready().await?; + let codec = tonic::codec::ProstCodec::new(); + let path = http::uri::PathAndQuery::from_static("/routeguide.RouteGuide/ListFeatures"); + self.inner.server_streaming(request, path, codec).await + } + pub async fn record_route( + &mut self, + request: tonic::Request, + ) -> Result, tonic::Status> + where + S: tonic::_codegen::Stream> + Send + 'static, + { + self.ready().await?; + let codec = tonic::codec::ProstCodec::new(); + let path = http::uri::PathAndQuery::from_static("/routeguide.RouteGuide/RecordRoute"); + let request = request.map(|s| Box::pin(s)); + self.inner.client_streaming(request, path, codec).await + } + pub async fn route_chat( + &mut self, + request: tonic::Request, + ) -> Result>, tonic::Status> + where + S: tonic::_codegen::Stream> + Send + 'static, + { + self.ready().await?; + let codec = tonic::codec::ProstCodec::new(); + let path = http::uri::PathAndQuery::from_static("/routeguide.RouteGuide/RouteChat"); + let request = request.map(|s| Box::pin(s)); + self.inner.streaming(request, path, codec).await + } +} +impl Clone for RouteGuideClient { + fn clone(&self) -> Self { + Self { + inner: self.inner.clone(), + } + } +} diff --git a/tonic-build/Cargo.toml b/tonic-build/Cargo.toml index db4fcb1..5352567 100644 --- a/tonic-build/Cargo.toml +++ b/tonic-build/Cargo.toml @@ -8,6 +8,7 @@ edition = "2018" [dependencies] prost-build = "0.5" -codegen = "0.1" -serde_json = "1.0" -serde = { version = "1.0", features = ["derive"] } +syn = "1.0" +quote = "1.0" +proc-macro2 = "1.0" +rustfmt = "0.10" diff --git a/tonic-macros/src/client.rs b/tonic-build/src/client.rs similarity index 71% rename from tonic-macros/src/client.rs rename to tonic-build/src/client.rs index fa1ceec..06bbe6a 100644 --- a/tonic-macros/src/client.rs +++ b/tonic-build/src/client.rs @@ -1,9 +1,50 @@ -use super::{Method, Service}; use proc_macro2::TokenStream; +use prost_build::{Method, Service}; use quote::{format_ident, quote}; use syn::Path; -pub(crate) fn generate(service: Service, proto: String) -> TokenStream { +pub(crate) fn generate(service: &Service, proto: &str) -> TokenStream { + let service_ident = quote::format_ident!("{}Client", service.name); + let methods = generate_methods(service, proto); + + quote! { + use tonic::_codegen::*; + + pub struct #service_ident { + inner: tonic::client::Grpc, + } + + impl #service_ident + where T: tonic::client::GrpcService, + T::ResponseBody: tonic::body::Body + tonic::_codegen::HttpBody + Send + 'static, + T::Error: Into, + ::Error: Into + Send, + ::Data: Into + Send, { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + + pub async fn ready(&mut self) -> Result<(), tonic::Status> { + self.inner.ready().await.map_err(|e| { + tonic::Status::new(tonic::Code::Unknown, format!("Service was not ready: {}", e.into())) + }) + } + + #methods + } + + impl Clone for #service_ident { + fn clone(&self) -> Self { + Self { + inner: self.inner.clone(), + } + } + } + } +} + +fn generate_methods(service: &Service, proto: &str) -> TokenStream { let mut stream = TokenStream::new(); for method in &service.methods { diff --git a/tonic-build/src/lib.rs b/tonic-build/src/lib.rs index dad097f..3f6496e 100644 --- a/tonic-build/src/lib.rs +++ b/tonic-build/src/lib.rs @@ -1,95 +1,50 @@ use prost_build::Config; -use serde::Serialize; -use std::{io, path}; +use std::{io, path, process::Command}; -pub fn compile_protos

(protos: &[P], includes: &[P]) -> io::Result<()> +mod client; +mod service; + +pub fn compile_protos

(protos: &[P], includes: &[P], package: &str) -> io::Result<()> where P: AsRef, { + let out_dir = std::env::var("OUT_DIR").unwrap(); let mut config = Config::new(); config.service_generator(Box::new(ServiceGenerator {})); + config.out_dir(&out_dir); + config.compile_protos(protos, includes)?; - config.compile_protos(protos, includes) + fmt(&out_dir, &format!("{}.rs", package)); + + Ok(()) +} + +fn fmt(out_dir: &str, file: &str) { + let out = Command::new("rustfmt") + .arg("--emit") + .arg("files") + .arg("--edition") + .arg("2018") + .arg(format!("{}/{}", out_dir, file)) + .output() + .unwrap(); + + println!("out: {:?}", out); + assert!(out.status.success()); } pub struct ServiceGenerator {} impl prost_build::ServiceGenerator for ServiceGenerator { - fn generate(&mut self, service: prost_build::Service, _buf: &mut String) { - let file = format!( - "{}/{}.{}.json", - std::env::var("OUT_DIR").unwrap(), - service.package, - service.name - ); + fn generate(&mut self, service: prost_build::Service, buf: &mut String) { + let path = "self"; + let server = service::generate(&service, path); + let code = format!("{}", server); + buf.push_str(&code); - let svc = Service { - name: service.name, - proto_name: service.proto_name, - package: service.package, - methods: service - .methods - .into_iter() - .map(|m| Method { - name: m.name, - proto_name: m.proto_name, - input_type: m.input_type, - output_type: m.output_type, - input_proto_type: m.input_proto_type, - output_proto_type: m.output_proto_type, - client_streaming: m.client_streaming, - server_streaming: m.server_streaming, - }) - .collect(), - }; - - let json = serde_json::to_string(&svc).unwrap(); - - std::fs::write(file, json).unwrap(); + let client = client::generate(&service, path); + let code = format!("{}", client); + buf.push_str(&code); } - - // fn finalize(&mut self, buf: &mut String) { - // let mut fmt = codegen::Formatter::new(buf); - // self.scope - // .fmt(&mut fmt) - // .expect("formatting root scope failed!"); - // self.scope = codegen::Scope::new(); - // } -} - -/// A service descriptor. -#[derive(Debug, Serialize)] -pub struct Service { - /// The service name in Rust style. - pub name: String, - /// The service name as it appears in the .proto file. - pub proto_name: String, - /// The package name as it appears in the .proto file. - pub package: String, - /// The service methods. - pub methods: Vec, -} - -/// A service method descriptor. -#[derive(Debug, Serialize)] -pub struct Method { - /// The name of the method in Rust style. - pub name: String, - /// The name of the method as it appears in the .proto file. - pub proto_name: String, - /// The input Rust type. - pub input_type: String, - /// The output Rust type. - pub output_type: String, - /// The input Protobuf type. - pub input_proto_type: String, - /// The output Protobuf type. - pub output_proto_type: String, - // /// The method options. - // pub options: prost_types::MethodOptions, - /// Identifies if client streams multiple client messages. - pub client_streaming: bool, - /// Identifies if server streams multiple server messages. - pub server_streaming: bool, } diff --git a/tonic-build/src/service.rs b/tonic-build/src/service.rs new file mode 100644 index 0000000..081bfa6 --- /dev/null +++ b/tonic-build/src/service.rs @@ -0,0 +1,355 @@ +use proc_macro2::{Span, TokenStream}; +use prost_build::{Method, Service}; +use quote::quote; +use syn::{Ident, Lit, LitStr, Path}; + +pub(crate) fn generate(service: &Service, proto_path: &str) -> TokenStream { + let methods = generate_methods(&service, proto_path); + + 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); + let generated_trait = generate_trait(service, proto_path, server_trait.clone()); + + quote! { + use tonic::_codegen::*; + + #generated_trait + + // TODO: impl debug + #[derive(Clone)] + pub struct #server_make_service { + inner: std::sync::Arc, + } + + // TODO: impl debug + pub struct #server_service { + inner: std::sync::Arc, + } + + impl #server_make_service { + pub fn new(inner: T) -> Self { + let inner = std::sync::Arc::new(inner); + Self { inner } + } + } + + impl #server_service { + pub fn new(inner: std::sync::Arc) -> Self { + Self { inner } + } + } + + impl Service for #server_make_service { + type Response = #server_service ; + type Error = tonic::error::Never; + type Future = Ready>; + + fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll> { + Poll::Ready(Ok(())) + } + + fn call(&mut self, _: R) -> Self::Future { + ok(#server_service ::new(self.inner.clone())) + } + } + + impl Service> for #server_service { + type Response = http::Response; + type Error = tonic::error::Never; + type Future = BoxFuture; + + fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll> { + Poll::Ready(Ok(())) + } + + fn call(&mut self, req: http::Request) -> Self::Future { + let inner = self.inner.clone(); + + match req.uri().path() { + #methods + + _ => unimplemented!("use grpc unimplemented"), + } + } + } + } +} + +fn generate_trait(service: &Service, proto_path: &str, server_trait: Ident) -> TokenStream { + let methods = generate_trait_methods(service, proto_path); + + quote! { + #[async_trait] + pub trait #server_trait : Send + Sync + 'static { + #methods + + } + } +} + +fn generate_trait_methods(service: &Service, proto_path: &str) -> TokenStream { + let mut stream = TokenStream::new(); + + 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 method = match (method.client_streaming, method.server_streaming) { + (false, false) => { + quote! { + async fn #name (&self, request: tonic::Request<#req_message>) + -> Result, tonic::Status>; + } + } + (true, false) => { + quote! { + async fn #name (&self, request: tonic::Request>) + -> Result, tonic::Status>; + } + } + (false, true) => { + let stream = quote::format_ident!("{}Stream", method.proto_name); + + quote! { + type #stream: Stream> + Unpin + Send + 'static; + + async fn #name (&self, request: tonic::Request<#req_message>) + -> Result, tonic::Status>; + } + } + (true, true) => { + let stream = quote::format_ident!("{}Stream", method.proto_name); + + quote! { + type #stream: Stream> + Unpin + Send + 'static; + + async fn #name (&self, request: tonic::Request>) + -> Result, tonic::Status>; + } + } + }; + + stream.extend(method); + } + + stream +} + +fn generate_methods(service: &Service, proto_path: &str) -> TokenStream { + let mut stream = TokenStream::new(); + + 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, proto_path, server_trait), + + (false, true) => { + generate_server_streaming(method, ident.clone(), proto_path, server_trait) + } + (true, false) => { + generate_client_streaming(method, ident.clone(), proto_path, server_trait) + } + + (true, true) => generate_streaming(method, ident.clone(), proto_path, server_trait), + }; + + let method = quote! { + #method_path => { + #method_stream + } + }; + stream.extend(method); + } + + stream +} + +fn generate_unary( + method: &Method, + method_ident: Ident, + proto_path: &str, + server_trait: Ident, +) -> 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(); + + quote! { + struct #service_ident (pub std::sync::Arc); + + impl tonic::server::UnaryService<#request> for #service_ident { + type Response = #response; + 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 + }; + 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.unary(method, req).await; + Ok(res) + }; + + // TODO: implement this future manually + Box::pin(fut) + } +} + +fn generate_server_streaming( + method: &Method, + method_ident: Ident, + proto_path: &str, + server_trait: Ident, +) -> 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 response_stream = quote::format_ident!("{}Stream", method.proto_name); + + // 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); + + impl tonic::server::ServerStreamingService<#request> for #service_ident { + type Response = #response; + type ResponseStream = T::#response_stream; + 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 + + }; + 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) + }; + + Box::pin(fut) + } +} + +fn generate_client_streaming( + method: &Method, + method_ident: Ident, + proto_path: &str, + server_trait: Ident, +) -> 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(); + + quote! { + struct #service_ident(pub std::sync::Arc); + + impl tonic::server::ClientStreamingService<#request> for #service_ident + { + 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 + + }; + 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) + }; + + Box::pin(fut) + } +} + +fn generate_streaming( + method: &Method, + method_ident: Ident, + proto_path: &str, + server_trait: Ident, +) -> 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 response_stream = quote::format_ident!("{}Stream", method.proto_name); + + // 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); + + impl tonic::server::StreamingService<#request> for #service_ident + { + type Response = #response; + type ResponseStream = T::#response_stream; + 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 + }; + 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) + }; + + Box::pin(fut) + } +} diff --git a/tonic-examples/Cargo.toml b/tonic-examples/Cargo.toml index 1d3353d..8517db8 100644 --- a/tonic-examples/Cargo.toml +++ b/tonic-examples/Cargo.toml @@ -4,8 +4,6 @@ version = "0.1.0" authors = ["Lucio Franco "] edition = "2018" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - [[bin]] name = "helloworld-server" path = "src/helloworld/server.rs" @@ -14,9 +12,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/build.rs b/tonic-examples/build.rs index 6760737..9b8990f 100644 --- a/tonic-examples/build.rs +++ b/tonic-examples/build.rs @@ -2,12 +2,14 @@ fn main() { tonic_build::compile_protos( &["proto/helloworld/helloworld.proto"], &["proto/helloworld"], + "helloworld", ) .unwrap(); tonic_build::compile_protos( &["proto/routeguide/route_guide.proto"], &["proto/routeguide"], + "routeguide", ) .unwrap(); } diff --git a/tonic-examples/src/helloworld/client.rs b/tonic-examples/src/helloworld/client.rs index 097c7c4..4ad3fae 100644 --- a/tonic-examples/src/helloworld/client.rs +++ b/tonic-examples/src/helloworld/client.rs @@ -2,7 +2,6 @@ use tonic::transport::Channel; pub mod hello_world { include!(concat!(env!("OUT_DIR"), "/helloworld.rs")); - tonic::client!(service = "helloworld.Greeter", proto = "self"); } #[tokio::main] diff --git a/tonic-examples/src/helloworld/server.rs b/tonic-examples/src/helloworld/server.rs index 043e85a..c7e464b 100644 --- a/tonic-examples/src/helloworld/server.rs +++ b/tonic-examples/src/helloworld/server.rs @@ -1,18 +1,20 @@ -use tonic::{Request, Response, Status, Server}; +use tonic::{Request, Response, Server, Status}; pub mod hello_world { include!(concat!(env!("OUT_DIR"), "/helloworld.rs")); - tonic::server!(service = "helloworld.Greeter", proto = "self"); } -#[derive(Default, Clone)] +#[derive(Default)] pub struct MyGreeter { data: String, } -#[tonic::server_trait] +#[tonic::async_trait] impl hello_world::Greeter for MyGreeter { - async fn say_hello(self, request: Request) -> Result, Status> { + async fn say_hello( + &self, + request: Request, + ) -> Result, Status> { println!("Got a request: {:?}", request); let string = &self.data; diff --git a/tonic-examples/src/routeguide/client.rs b/tonic-examples/src/routeguide/client.rs index 725cbee..455a152 100644 --- a/tonic-examples/src/routeguide/client.rs +++ b/tonic-examples/src/routeguide/client.rs @@ -6,7 +6,6 @@ use tonic::{transport::Channel, Request}; mod route_guide { include!(concat!(env!("OUT_DIR"), "/routeguide.rs")); - tonic::client!(service = "routeguide.RouteGuide", proto = "self"); } #[tokio::main] diff --git a/tonic-examples/src/routeguide/server.rs b/tonic-examples/src/routeguide/server.rs index 323e287..74e181b 100644 --- a/tonic-examples/src/routeguide/server.rs +++ b/tonic-examples/src/routeguide/server.rs @@ -8,6 +8,7 @@ use std::time::Instant; use tokio::sync::{mpsc, Lock}; use tonic::transport::Server; use tonic::{Request, Response, Status}; +use std::pin::Pin; pub mod routeguide { include!(concat!(env!("OUT_DIR"), "/routeguide.rs")); @@ -26,9 +27,9 @@ struct State { notes: Lock>>, } -#[tonic::server(service = "routeguide.RouteGuide", proto = "routeguide")] -impl RouteGuide { - pub async fn get_feature(&self, request: Request) -> Result, Status> { +#[tonic::async_trait] +impl routeguide::RouteGuide for RouteGuide { + async fn get_feature(&self, request: Request) -> Result, Status> { println!("GetFeature = {:?}", request); for feature in &self.state.features[..] { @@ -45,10 +46,12 @@ impl RouteGuide { Ok(response) } - pub async fn list_features( + type ListFeaturesStream = mpsc::Receiver>; + + async fn list_features( &self, request: Request, - ) -> Result>>, Status> { + ) -> Result, Status> { use std::thread; println!("ListFeatures = {:?}", request); @@ -71,9 +74,9 @@ impl RouteGuide { Ok(Response::new(rx)) } - pub async fn record_route( + async fn record_route( &self, - request: Request>>, + request: Request>, ) -> Result, Status> { println!("RecordRoute"); @@ -114,10 +117,12 @@ impl RouteGuide { Ok(Response::new(summary)) } - pub async fn route_chat( + type RouteChatStream = Pin> + Send + 'static>>; + + async fn route_chat( &self, - request: Request> + Send + 'static>, - ) -> Result> + Send>, Status> { + request: Request>, + ) -> Result, Status> { println!("RouteChat"); let stream = request.into_inner(); @@ -141,7 +146,8 @@ impl RouteGuide { } }; - Ok(Response::new(output)) + // TODO: Clean this up + Ok(Response::new(Box::pin(output) as Pin> + Send + 'static>>)) } } @@ -159,8 +165,10 @@ async fn main() -> Result<(), Box> { }, }; + let svc = routeguide::RouteGuideServer::new(route_guide); + Server::builder() - .serve(addr, RouteGuideServer::new(route_guide)) + .serve(addr, svc) .await?; Ok(()) diff --git a/tonic-macros/Cargo.toml b/tonic-macros/Cargo.toml deleted file mode 100644 index 64939f1..0000000 --- a/tonic-macros/Cargo.toml +++ /dev/null @@ -1,15 +0,0 @@ -[package] -name = "tonic-macros" -version = "0.1.0" -authors = ["Lucio Franco "] -edition = "2018" - -[lib] -proc-macro = true - -[dependencies] -syn = { version = "1.0", features = ["full"] } -quote = "1.0" -proc-macro2 = "1.0" -serde_json = "1.0" -serde = { version = "1.0", features = ["derive"] } diff --git a/tonic-macros/src/lib.rs b/tonic-macros/src/lib.rs deleted file mode 100644 index 255d8f5..0000000 --- a/tonic-macros/src/lib.rs +++ /dev/null @@ -1,155 +0,0 @@ -#![recursion_limit = "256"] - -extern crate proc_macro; - -mod client; -mod service; - -use proc_macro::TokenStream; -use quote::quote; -use serde::Deserialize; -use syn::{AttributeArgs, ItemImpl}; - -#[proc_macro] -pub fn client(attr: TokenStream) -> TokenStream { - let args = syn::parse_macro_input!(attr as AttributeArgs); - let (service, proto_path) = load_service(args); - - let service_ident = quote::format_ident!("{}Client", service.name); - let methods = client::generate(service, proto_path); - - let output = quote! { - use tonic::_codegen::*; - - pub struct #service_ident { - inner: tonic::client::Grpc, - } - - impl #service_ident - where T: tonic::client::GrpcService, - T::ResponseBody: tonic::body::Body + tonic::_codegen::HttpBody + Send + 'static, - T::Error: Into, - ::Error: Into + Send, - ::Data: Into + Send, { - pub fn new(inner: T) -> Self { - let inner = tonic::client::Grpc::new(inner); - Self { inner } - } - - pub async fn ready(&mut self) -> Result<(), tonic::Status> { - self.inner.ready().await.map_err(|e| { - tonic::Status::new(tonic::Code::Unknown, format!("Service was not ready: {}", e.into())) - }) - } - - #methods - } - - impl Clone for #service_ident { - fn clone(&self) -> Self { - Self { - inner: self.inner.clone(), - } - } - } - }; - - TokenStream::from(output) -} - -#[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 output = service::generate(service, &proto_path); - - TokenStream::from(output) -} - -fn load_service(attr: AttributeArgs) -> (Service, String) { - use syn::{Lit, Meta, MetaNameValue, NestedMeta}; - - let service = attr - .iter() - .filter_map(|i| match i { - NestedMeta::Meta(Meta::NameValue(MetaNameValue { path, lit, .. })) - if path.segments.first().unwrap().ident == "service" => - { - Some(lit.clone()) - } - _ => None, - }) - .next(); - - let service_name = match service { - Some(Lit::Str(s)) => s.value(), - Some(_) => panic!("expected a literal string"), - None => panic!("expected a `service = \"package.Service\" attribute"), - }; - - let service = attr - .iter() - .filter_map(|i| match i { - NestedMeta::Meta(Meta::NameValue(MetaNameValue { path, lit, .. })) - if path.segments.first().unwrap().ident == "proto" => - { - Some(lit.clone()) - } - _ => None, - }) - .next(); - - let proto_path = match service { - Some(Lit::Str(s)) => s.value(), - Some(_) => panic!("expected a literal string"), - None => panic!("expected a `proto = \"my::proto::path\" attribute"), - }; - - let file = format!( - "{}/{}.json", - std::env::var("OUT_DIR").unwrap(), - service_name - ); - let json = std::fs::read_to_string(file).unwrap(); - let svc = serde_json::from_str(&json).unwrap(); - - (svc, proto_path) -} - -/// A service descriptor. -#[derive(Debug, Deserialize)] -pub(crate) struct Service { - /// The service name in Rust style. - pub name: String, - /// The service name as it appears in the .proto file. - pub proto_name: String, - /// The package name as it appears in the .proto file. - pub package: String, - /// The service methods. - pub methods: Vec, -} - -/// A service method descriptor. -#[derive(Debug, Deserialize)] -pub(crate) struct Method { - /// The name of the method in Rust style. - pub name: String, - /// The name of the method as it appears in the .proto file. - pub proto_name: String, - /// The input Rust type. - pub input_type: String, - /// The output Rust type. - pub output_type: String, - /// The input Protobuf type. - pub input_proto_type: String, - /// The output Protobuf type. - pub output_proto_type: String, - // /// The method options. - // pub options: prost_types::MethodOptions, - /// Identifies if client streams multiple client messages. - pub client_streaming: bool, - /// Identifies if server streams multiple server messages. - pub server_streaming: bool, -} diff --git a/tonic-macros/src/service.rs b/tonic-macros/src/service.rs deleted file mode 100644 index 3304db5..0000000 --- a/tonic-macros/src/service.rs +++ /dev/null @@ -1,315 +0,0 @@ -use crate::{Method, Service}; -use proc_macro2::{Span, TokenStream}; -use quote::quote; -use syn::{Ident, Lit, LitStr, Path}; - -pub(crate) fn generate(service: Service, proto_path: &str) -> TokenStream { - let methods = generate_methods(&service, proto_path); - - 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: T, - } - - // TODO: impl debug - pub struct #server_service { - inner: T, - } - - impl #server_make_service { - pub fn new(inner: T) -> Self { - Self { inner } - } - } - - impl #server_service { - pub fn new(inner: T) -> Self { - Self { inner } - } - } - - impl Service for #server_make_service { - type Response = #server_service ; - type Error = tonic::error::Never; - type Future = Ready>; - - fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll> { - Poll::Ready(Ok(())) - } - - fn call(&mut self, _: R) -> Self::Future { - ok(#server_service ::new(self.inner.clone())) - } - } - - impl Service> for #server_service { - type Response = http::Response; - type Error = tonic::error::Never; - type Future = BoxFuture; - - fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll> { - Poll::Ready(Ok(())) - } - - fn call(&mut self, req: http::Request) -> Self::Future { - let inner = self.inner.clone(); - - match req.uri().path() { - #methods - - _ => unimplemented!("use grpc unimplemented"), - } - } - } - } -} - -fn generate_methods(service: &Service, proto_path: &str) -> TokenStream { - let mut stream = TokenStream::new(); - - 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, - proto_path, - server_trait - ), - - _ => unimplemented!() - - // (false, true) => generate_server_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! { - #method_path => { - #method_stream - } - }; - stream.extend(method); - } - - stream -} - -fn generate_unary( - method: &Method, - method_ident: Ident, - proto_path: &str, - server_trait: Ident, -) -> 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(); - - quote! { - struct #service_ident (pub T); - - impl tonic::server::UnaryService<#request> for #service_ident { - type Response = #response; - 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 - }; - 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.unary(method, req).await; - Ok(res) - }; - - // TODO: implement this future manually - Box::pin(fut) - } -} - -// 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(); - -// // 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>; - -// 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) -// } -// } - -// 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) -// } -// } - -// 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(); - -// 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>; - -// 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) -// } -// } - -// 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) -// } -// } - -// 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(); - -// // 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>; - -// 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) -// } -// } - -// 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) -// } -// } diff --git a/tonic/Cargo.toml b/tonic/Cargo.toml index 3ac0168..d5ae6fa 100644 --- a/tonic/Cargo.toml +++ b/tonic/Cargo.toml @@ -7,7 +7,6 @@ edition = "2018" [dependencies] futures-core-preview = "=0.3.0-alpha.18" futures-util-preview = "=0.3.0-alpha.18" -tonic-macros = { path = "../tonic-macros" } tracing = "0.1" http = "0.1.14" base64 = "0.10" diff --git a/tonic/src/lib.rs b/tonic/src/lib.rs index 1552f7c..33d706c 100644 --- a/tonic/src/lib.rs +++ b/tonic/src/lib.rs @@ -45,20 +45,19 @@ mod request; mod response; mod status; +pub use async_trait::async_trait; #[doc(inline, hidden)] pub use body::BoxBody; +#[doc(inline)] +pub use codec::Streaming; 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; diff --git a/tonic/src/server/grpc.rs b/tonic/src/server/grpc.rs index b7c5306..d53a86c 100644 --- a/tonic/src/server/grpc.rs +++ b/tonic/src/server/grpc.rs @@ -93,7 +93,7 @@ where req: http::Request, ) -> http::Response where - S: ClientStreamingService, Response = T::Encode>, + S: ClientStreamingService, B: Body + Send + 'static, B::Data: Into + Send + 'static, B::Error: Into + Send + 'static, @@ -113,7 +113,7 @@ where req: http::Request, ) -> http::Response where - S: StreamingService, Response = T::Encode> + Send, + S: StreamingService + Send, S::ResponseStream: Send + 'static, B: Body + Send + 'static, B::Data: Into + Send, diff --git a/tonic/src/server/service.rs b/tonic/src/server/service.rs index 39f5ace..3842d78 100644 --- a/tonic/src/server/service.rs +++ b/tonic/src/server/service.rs @@ -1,4 +1,4 @@ -use crate::{Request, Response, Status}; +use crate::{Request, Response, Status, Streaming}; use futures_core::Stream; use std::future::Future; use tower_service::Service; @@ -66,7 +66,7 @@ where /// /// Existing tower_service::Service implementations with the correct form will /// automatically implement `ClientStreamingService`. -pub trait ClientStreamingService { +pub trait ClientStreamingService { /// Protobuf response message type type Response; @@ -74,18 +74,17 @@ pub trait ClientStreamingService { type Future: Future, Status>>; /// Call the service - fn call(&mut self, request: Request) -> Self::Future; + fn call(&mut self, request: Request>) -> Self::Future; } -impl ClientStreamingService for T +impl ClientStreamingService for T where - T: Service, Response = Response, Error = crate::Status>, - S: Stream>, + T: Service>, Response = Response, Error = crate::Status>, { type Response = M2; type Future = T::Future; - fn call(&mut self, request: Request) -> Self::Future { + fn call(&mut self, request: Request>) -> Self::Future { Service::call(self, request) } } @@ -94,7 +93,7 @@ where /// /// Existing tower_service::Service implementations with the correct form will /// automatically implement `StreamingService`. -pub trait StreamingService { +pub trait StreamingService { /// Protobuf response message type type Response; @@ -105,20 +104,19 @@ pub trait StreamingService { type Future: Future, Status>>; /// Call the service - fn call(&mut self, request: Request) -> Self::Future; + fn call(&mut self, request: Request>) -> Self::Future; } -impl StreamingService for T +impl StreamingService for T where - T: Service, Response = Response, Error = crate::Status>, - S1: Stream>, - S2: Stream>, + T: Service>, Response = Response, Error = crate::Status>, + S: Stream>, { type Response = M2; - type ResponseStream = S2; + type ResponseStream = S; type Future = T::Future; - fn call(&mut self, request: Request) -> Self::Future { + fn call(&mut self, request: Request>) -> Self::Future { Service::call(self, request) } }