Move codegen to build and remove macros

This commit is contained in:
Lucio Franco
2019-09-06 15:19:18 -04:00
parent 295e7321b9
commit d0cfafafc6
20 changed files with 916 additions and 615 deletions
-1
View File
@@ -1,7 +1,6 @@
[workspace]
members = [
"tonic",
"tonic-macros",
"tonic-build",
"tonic-examples",
# "tonic-interop",
+128
View File
@@ -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<self::HelloRequest>,
) -> Result<tonic::Response<self::HelloReply>, tonic::Status>;
}
#[derive(Clone)]
pub struct GreeterServer<T: Greeter> {
inner: std::sync::Arc<T>,
}
pub struct GreeterServerSvc<T: Greeter> {
inner: std::sync::Arc<T>,
}
impl<T: Greeter> GreeterServer<T> {
pub fn new(inner: T) -> Self {
let inner = std::sync::Arc::new(inner);
Self { inner }
}
}
impl<T: Greeter> GreeterServerSvc<T> {
pub fn new(inner: std::sync::Arc<T>) -> Self {
Self { inner }
}
}
impl<T: Greeter, R> Service<R> for GreeterServer<T> {
type Response = GreeterServerSvc<T>;
type Error = tonic::error::Never;
type Future = Ready<Result<Self::Response, Self::Error>>;
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
fn call(&mut self, _: R) -> Self::Future {
ok(GreeterServerSvc::new(self.inner.clone()))
}
}
impl<T: Greeter> Service<http::Request<tonic::_codegen::HyperBody>> for GreeterServerSvc<T> {
type Response = http::Response<tonic::BoxBody>;
type Error = tonic::error::Never;
type Future = BoxFuture<Self::Response, Self::Error>;
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
fn call(&mut self, req: http::Request<tonic::_codegen::HyperBody>) -> Self::Future {
let inner = self.inner.clone();
match req.uri().path() {
"/helloworld.Greeter/SayHello" => {
struct SayHello<T: Greeter>(pub std::sync::Arc<T>);
impl<T: Greeter> tonic::server::UnaryService<self::HelloRequest> for SayHello<T> {
type Response = self::HelloReply;
type Future = BoxFuture<tonic::Response<Self::Response>, tonic::Status>;
fn call(
&mut self,
request: tonic::Request<self::HelloRequest>,
) -> 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<T> {
inner: tonic::client::Grpc<T>,
}
impl<T> GreeterClient<T>
where
T: tonic::client::GrpcService<tonic::BoxBody>,
T::ResponseBody: tonic::body::Body + tonic::_codegen::HttpBody + Send + 'static,
T::Error: Into<tonic::error::Error>,
<T::ResponseBody as tonic::_codegen::HttpBody>::Error: Into<tonic::error::Error> + Send,
<T::ResponseBody as tonic::_codegen::HttpBody>::Data: Into<bytes::Bytes> + 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<self::HelloRequest>,
) -> Result<tonic::Response<self::HelloReply>, 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<T: Clone> Clone for GreeterClient<T> {
fn clone(&self) -> Self {
Self {
inner: self.inner.clone(),
}
}
}
+303
View File
@@ -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<Point>,
/// The other corner of the rectangle.
#[prost(message, optional, tag = "2")]
pub hi: ::std::option::Option<Point>,
}
/// 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<Point>,
}
/// 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<Point>,
/// 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<self::Point>,
) -> Result<tonic::Response<self::Feature>, tonic::Status>;
type ListFeaturesStream: Stream<Item = Result<self::Feature, tonic::Status>>
+ Unpin
+ Send
+ 'static;
async fn list_features(
&self,
request: tonic::Request<self::Rectangle>,
) -> Result<tonic::Response<Self::ListFeaturesStream>, tonic::Status>;
async fn record_route(
&self,
request: tonic::Request<tonic::Streaming<self::Point>>,
) -> Result<tonic::Response<self::RouteSummary>, tonic::Status>;
type RouteChatStream: Stream<Item = Result<self::RouteNote, tonic::Status>>
+ Unpin
+ Send
+ 'static;
async fn route_chat(
&self,
request: tonic::Request<tonic::Streaming<self::RouteNote>>,
) -> Result<tonic::Response<Self::RouteChatStream>, tonic::Status>;
}
#[derive(Clone)]
pub struct RouteGuideServer<T: RouteGuide> {
inner: std::sync::Arc<T>,
}
pub struct RouteGuideServerSvc<T: RouteGuide> {
inner: std::sync::Arc<T>,
}
impl<T: RouteGuide> RouteGuideServer<T> {
pub fn new(inner: T) -> Self {
let inner = std::sync::Arc::new(inner);
Self { inner }
}
}
impl<T: RouteGuide> RouteGuideServerSvc<T> {
pub fn new(inner: std::sync::Arc<T>) -> Self {
Self { inner }
}
}
impl<T: RouteGuide, R> Service<R> for RouteGuideServer<T> {
type Response = RouteGuideServerSvc<T>;
type Error = tonic::error::Never;
type Future = Ready<Result<Self::Response, Self::Error>>;
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
fn call(&mut self, _: R) -> Self::Future {
ok(RouteGuideServerSvc::new(self.inner.clone()))
}
}
impl<T: RouteGuide> Service<http::Request<tonic::_codegen::HyperBody>> for RouteGuideServerSvc<T> {
type Response = http::Response<tonic::BoxBody>;
type Error = tonic::error::Never;
type Future = BoxFuture<Self::Response, Self::Error>;
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
fn call(&mut self, req: http::Request<tonic::_codegen::HyperBody>) -> Self::Future {
let inner = self.inner.clone();
match req.uri().path() {
"/routeguide.RouteGuide/GetFeature" => {
struct GetFeature<T: RouteGuide>(pub std::sync::Arc<T>);
impl<T: RouteGuide> tonic::server::UnaryService<self::Point> for GetFeature<T> {
type Response = self::Feature;
type Future = BoxFuture<tonic::Response<Self::Response>, tonic::Status>;
fn call(&mut self, request: tonic::Request<self::Point>) -> 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<T: RouteGuide>(pub std::sync::Arc<T>);
impl<T: RouteGuide> tonic::server::ServerStreamingService<self::Rectangle> for ListFeatures<T> {
type Response = self::Feature;
type ResponseStream = T::ListFeaturesStream;
type Future = BoxFuture<tonic::Response<Self::ResponseStream>, tonic::Status>;
fn call(&mut self, request: tonic::Request<self::Rectangle>) -> 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<T: RouteGuide>(pub std::sync::Arc<T>);
impl<T: RouteGuide> tonic::server::ClientStreamingService<self::Point> for RecordRoute<T> {
type Response = self::RouteSummary;
type Future = BoxFuture<tonic::Response<Self::Response>, tonic::Status>;
fn call(
&mut self,
request: tonic::Request<tonic::Streaming<self::Point>>,
) -> 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<T: RouteGuide>(pub std::sync::Arc<T>);
impl<T: RouteGuide> tonic::server::StreamingService<self::RouteNote> for RouteChat<T> {
type Response = self::RouteNote;
type ResponseStream = T::RouteChatStream;
type Future = BoxFuture<tonic::Response<Self::ResponseStream>, tonic::Status>;
fn call(
&mut self,
request: tonic::Request<tonic::Streaming<self::RouteNote>>,
) -> 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<T> {
inner: tonic::client::Grpc<T>,
}
impl<T> RouteGuideClient<T>
where
T: tonic::client::GrpcService<tonic::BoxBody>,
T::ResponseBody: tonic::body::Body + tonic::_codegen::HttpBody + Send + 'static,
T::Error: Into<tonic::error::Error>,
<T::ResponseBody as tonic::_codegen::HttpBody>::Error: Into<tonic::error::Error> + Send,
<T::ResponseBody as tonic::_codegen::HttpBody>::Data: Into<bytes::Bytes> + 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<self::Point>,
) -> Result<tonic::Response<self::Feature>, 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<self::Rectangle>,
) -> Result<tonic::Response<tonic::codec::Streaming<self::Feature>>, 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<S>(
&mut self,
request: tonic::Request<S>,
) -> Result<tonic::Response<self::RouteSummary>, tonic::Status>
where
S: tonic::_codegen::Stream<Item = Result<self::Point, tonic::Status>> + 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<S>(
&mut self,
request: tonic::Request<S>,
) -> Result<tonic::Response<tonic::codec::Streaming<self::RouteNote>>, tonic::Status>
where
S: tonic::_codegen::Stream<Item = Result<self::RouteNote, tonic::Status>> + 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<T: Clone> Clone for RouteGuideClient<T> {
fn clone(&self) -> Self {
Self {
inner: self.inner.clone(),
}
}
}
+4 -3
View File
@@ -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"
@@ -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 <T> {
inner: tonic::client::Grpc<T>,
}
impl<T> #service_ident <T>
where T: tonic::client::GrpcService<tonic::BoxBody>,
T::ResponseBody: tonic::body::Body + tonic::_codegen::HttpBody + Send + 'static,
T::Error: Into<tonic::error::Error>,
<T::ResponseBody as tonic::_codegen::HttpBody>::Error: Into<tonic::error::Error> + Send,
<T::ResponseBody as tonic::_codegen::HttpBody>::Data: Into<bytes::Bytes> + 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<T: Clone> Clone for #service_ident <T> {
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 {
+33 -78
View File
@@ -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<P>(protos: &[P], includes: &[P]) -> io::Result<()>
mod client;
mod service;
pub fn compile_protos<P>(protos: &[P], includes: &[P], package: &str) -> io::Result<()>
where
P: AsRef<path::Path>,
{
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<Method>,
}
/// 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,
}
+355
View File
@@ -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 <T: #server_trait > {
inner: std::sync::Arc<T>,
}
// TODO: impl debug
pub struct #server_service <T: #server_trait > {
inner: std::sync::Arc<T>,
}
impl<T: #server_trait > #server_make_service <T> {
pub fn new(inner: T) -> Self {
let inner = std::sync::Arc::new(inner);
Self { inner }
}
}
impl<T: #server_trait > #server_service <T> {
pub fn new(inner: std::sync::Arc<T>) -> Self {
Self { inner }
}
}
impl<T: #server_trait , R> Service<R> for #server_make_service <T> {
type Response = #server_service <T>;
type Error = tonic::error::Never;
type Future = Ready<Result<Self::Response, Self::Error>>;
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
fn call(&mut self, _: R) -> Self::Future {
ok(#server_service ::new(self.inner.clone()))
}
}
impl<T: #server_trait > Service<http::Request<tonic::_codegen::HyperBody>> for #server_service <T> {
type Response = http::Response<tonic::BoxBody>;
type Error = tonic::error::Never;
type Future = BoxFuture<Self::Response, Self::Error>;
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
fn call(&mut self, req: http::Request<tonic::_codegen::HyperBody>) -> 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::Response<#res_message>, tonic::Status>;
}
}
(true, false) => {
quote! {
async fn #name (&self, request: tonic::Request<tonic::Streaming<#req_message>>)
-> Result<tonic::Response<#res_message>, tonic::Status>;
}
}
(false, true) => {
let stream = quote::format_ident!("{}Stream", method.proto_name);
quote! {
type #stream: Stream<Item = Result<#res_message, tonic::Status>> + Unpin + Send + 'static;
async fn #name (&self, request: tonic::Request<#req_message>)
-> Result<tonic::Response<Self::#stream>, tonic::Status>;
}
}
(true, true) => {
let stream = quote::format_ident!("{}Stream", method.proto_name);
quote! {
type #stream: Stream<Item = Result<#res_message, tonic::Status>> + Unpin + Send + 'static;
async fn #name (&self, request: tonic::Request<tonic::Streaming<#req_message>>)
-> Result<tonic::Response<Self::#stream>, 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 <T: #server_trait >(pub std::sync::Arc<T>);
impl<T: #server_trait > tonic::server::UnaryService<#request> for #service_ident <T> {
type Response = #response;
type Future = BoxFuture<tonic::Response<Self::Response>, 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 <T: #server_trait >(pub std::sync::Arc<T>);
impl<T: #server_trait > tonic::server::ServerStreamingService<#request> for #service_ident <T> {
type Response = #response;
type ResponseStream = T::#response_stream;
type Future = BoxFuture<tonic::Response<Self::ResponseStream>, 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<T: #server_trait >(pub std::sync::Arc<T>);
impl<T: #server_trait> tonic::server::ClientStreamingService<#request> for #service_ident <T>
{
type Response = #response;
type Future = BoxFuture<tonic::Response<Self::Response>, tonic::Status>;
fn call(&mut self, request: tonic::Request<tonic::Streaming<#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<T: #server_trait >(pub std::sync::Arc<T>);
impl<T: #server_trait > tonic::server::StreamingService<#request> for #service_ident <T>
{
type Response = #response;
type ResponseStream = T::#response_stream;
type Future = BoxFuture<tonic::Response<Self::ResponseStream>, tonic::Status>;
fn call(&mut self, request: tonic::Request<tonic::Streaming<#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)
}
}
+3 -5
View File
@@ -4,8 +4,6 @@ version = "0.1.0"
authors = ["Lucio Franco <luciofranco14@gmail.com>"]
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"
+2
View File
@@ -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();
}
-1
View File
@@ -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]
+7 -5
View File
@@ -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<hello_world::HelloRequest>) -> Result<Response<hello_world::HelloReply>, Status> {
async fn say_hello(
&self,
request: Request<hello_world::HelloRequest>,
) -> Result<Response<hello_world::HelloReply>, Status> {
println!("Got a request: {:?}", request);
let string = &self.data;
-1
View File
@@ -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]
+20 -12
View File
@@ -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<HashMap<Point, Vec<RouteNote>>>,
}
#[tonic::server(service = "routeguide.RouteGuide", proto = "routeguide")]
impl RouteGuide {
pub async fn get_feature(&self, request: Request<Point>) -> Result<Response<Feature>, Status> {
#[tonic::async_trait]
impl routeguide::RouteGuide for RouteGuide {
async fn get_feature(&self, request: Request<Point>) -> Result<Response<Feature>, 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<Result<Feature, Status>>;
async fn list_features(
&self,
request: Request<Rectangle>,
) -> Result<Response<mpsc::Receiver<Result<Feature, Status>>>, Status> {
) -> Result<Response<Self::ListFeaturesStream>, 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<impl Stream<Item = Result<Point, Status>>>,
request: Request<tonic::Streaming<Point>>,
) -> Result<Response<RouteSummary>, Status> {
println!("RecordRoute");
@@ -114,10 +117,12 @@ impl RouteGuide {
Ok(Response::new(summary))
}
pub async fn route_chat(
type RouteChatStream = Pin<Box<dyn Stream<Item = Result<RouteNote, Status>> + Send + 'static>>;
async fn route_chat(
&self,
request: Request<impl Stream<Item = Result<RouteNote, Status>> + Send + 'static>,
) -> Result<Response<impl Stream<Item = Result<RouteNote, Status>> + Send>, Status> {
request: Request<tonic::Streaming<RouteNote>>,
) -> Result<Response<Self::RouteChatStream>, 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<Box<dyn Stream<Item = Result<RouteNote, Status>> + Send + 'static>>))
}
}
@@ -159,8 +165,10 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
},
};
let svc = routeguide::RouteGuideServer::new(route_guide);
Server::builder()
.serve(addr, RouteGuideServer::new(route_guide))
.serve(addr, svc)
.await?;
Ok(())
-15
View File
@@ -1,15 +0,0 @@
[package]
name = "tonic-macros"
version = "0.1.0"
authors = ["Lucio Franco <luciofranco14@gmail.com>"]
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"] }
-155
View File
@@ -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 <T> {
inner: tonic::client::Grpc<T>,
}
impl<T> #service_ident <T>
where T: tonic::client::GrpcService<tonic::BoxBody>,
T::ResponseBody: tonic::body::Body + tonic::_codegen::HttpBody + Send + 'static,
T::Error: Into<tonic::error::Error>,
<T::ResponseBody as tonic::_codegen::HttpBody>::Error: Into<tonic::error::Error> + Send,
<T::ResponseBody as tonic::_codegen::HttpBody>::Data: Into<bytes::Bytes> + 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<T: Clone> Clone for #service_ident <T> {
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<Method>,
}
/// 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,
}
-315
View File
@@ -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<self::HelloRequest>)
-> Result<tonic::Response<self::HelloReply>, tonic::Status>;
}
// TODO: impl debug
#[derive(Clone)]
pub struct #server_make_service <T: #server_trait > {
inner: T,
}
// TODO: impl debug
pub struct #server_service <T: #server_trait > {
inner: T,
}
impl<T: #server_trait > #server_make_service <T> {
pub fn new(inner: T) -> Self {
Self { inner }
}
}
impl<T: #server_trait > #server_service <T> {
pub fn new(inner: T) -> Self {
Self { inner }
}
}
impl<T: #server_trait , R> Service<R> for #server_make_service <T> {
type Response = #server_service <T>;
type Error = tonic::error::Never;
type Future = Ready<Result<Self::Response, Self::Error>>;
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
fn call(&mut self, _: R) -> Self::Future {
ok(#server_service ::new(self.inner.clone()))
}
}
impl<T: #server_trait > Service<http::Request<tonic::_codegen::HyperBody>> for #server_service <T> {
type Response = http::Response<tonic::BoxBody>;
type Error = tonic::error::Never;
type Future = BoxFuture<Self::Response, Self::Error>;
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
fn call(&mut self, req: http::Request<tonic::_codegen::HyperBody>) -> 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 <T: #server_trait >(pub T);
impl<T: #server_trait > tonic::server::UnaryService<#request> for #service_ident <T> {
type Response = #response;
type Future = BoxFuture<tonic::Response<Self::Response>, 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<Box<dyn Stream<Item = Result<Self::Response, Status>> + Send>>;
// type Future = BoxFuture<tonic::Response<Self::ResponseStream>, 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<Box<dyn Stream<Item = Result<Self::Response, Status>> + 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<S> tonic::server::ClientStreamingService<S> for #service_ident
// where S: tonic::_codegen::Stream<Item = Result<#request, Status>> + Unpin + Send + 'static {
// type Response = #response;
// type Future = BoxFuture<tonic::Response<Self::Response>, tonic::Status>;
// fn call(&mut self, request: tonic::Request<S>) -> 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<S> tonic::server::StreamingService<S> for #service_ident
// where S: Stream<Item = Result<#request, Status>> + Unpin + Send + 'static {
// type Response = #response;
// type ResponseStream = Pin<Box<dyn Stream<Item = Result<Self::Response, Status>> + Send>>;
// type Future = BoxFuture<tonic::Response<Self::ResponseStream>, tonic::Status>;
// fn call(&mut self, request: tonic::Request<S>) -> 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<Box<dyn Stream<Item = Result<Self::Response, Status>> + 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)
// }
// }
-1
View File
@@ -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"
+3 -4
View File
@@ -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;
+2 -2
View File
@@ -93,7 +93,7 @@ where
req: http::Request<B>,
) -> http::Response<BoxBody>
where
S: ClientStreamingService<Streaming<T::Decode>, Response = T::Encode>,
S: ClientStreamingService<T::Decode, Response = T::Encode>,
B: Body + Send + 'static,
B::Data: Into<Bytes> + Send + 'static,
B::Error: Into<crate::Error> + Send + 'static,
@@ -113,7 +113,7 @@ where
req: http::Request<B>,
) -> http::Response<BoxBody>
where
S: StreamingService<Streaming<T::Decode>, Response = T::Encode> + Send,
S: StreamingService<T::Decode, Response = T::Encode> + Send,
S::ResponseStream: Send + 'static,
B: Body + Send + 'static,
B::Data: Into<Bytes> + Send,
+13 -15
View File
@@ -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<RequestStream> {
pub trait ClientStreamingService<R> {
/// Protobuf response message type
type Response;
@@ -74,18 +74,17 @@ pub trait ClientStreamingService<RequestStream> {
type Future: Future<Output = Result<Response<Self::Response>, Status>>;
/// Call the service
fn call(&mut self, request: Request<RequestStream>) -> Self::Future;
fn call(&mut self, request: Request<Streaming<R>>) -> Self::Future;
}
impl<T, M1, M2, S> ClientStreamingService<S> for T
impl<T, M1, M2> ClientStreamingService<M1> for T
where
T: Service<Request<S>, Response = Response<M2>, Error = crate::Status>,
S: Stream<Item = Result<M1, crate::Status>>,
T: Service<Request<Streaming<M1>>, Response = Response<M2>, Error = crate::Status>,
{
type Response = M2;
type Future = T::Future;
fn call(&mut self, request: Request<S>) -> Self::Future {
fn call(&mut self, request: Request<Streaming<M1>>) -> 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<RequestStream> {
pub trait StreamingService<R> {
/// Protobuf response message type
type Response;
@@ -105,20 +104,19 @@ pub trait StreamingService<RequestStream> {
type Future: Future<Output = Result<Response<Self::ResponseStream>, Status>>;
/// Call the service
fn call(&mut self, request: Request<RequestStream>) -> Self::Future;
fn call(&mut self, request: Request<Streaming<R>>) -> Self::Future;
}
impl<T, S1, S2, M1, M2> StreamingService<S1> for T
impl<T, S, M1, M2> StreamingService<M1> for T
where
T: Service<Request<S1>, Response = Response<S2>, Error = crate::Status>,
S1: Stream<Item = Result<M1, crate::Status>>,
S2: Stream<Item = Result<M2, crate::Status>>,
T: Service<Request<Streaming<M1>>, Response = Response<S>, Error = crate::Status>,
S: Stream<Item = Result<M2, crate::Status>>,
{
type Response = M2;
type ResponseStream = S2;
type ResponseStream = S;
type Future = T::Future;
fn call(&mut self, request: Request<S1>) -> Self::Future {
fn call(&mut self, request: Request<Streaming<M1>>) -> Self::Future {
Service::call(self, request)
}
}