Add client, client codegen, helloworld and routeguide client examples
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
use super::{Method, Service};
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{format_ident, quote};
|
||||
use syn::Path;
|
||||
|
||||
pub(crate) fn generate(service: Service, proto: String) -> TokenStream {
|
||||
let mut stream = TokenStream::new();
|
||||
|
||||
for method in &service.methods {
|
||||
let path = format!(
|
||||
"/{}.{}/{}",
|
||||
service.package, service.proto_name, method.proto_name
|
||||
);
|
||||
|
||||
let method = match (method.client_streaming, method.server_streaming) {
|
||||
(false, false) => generate_unary(method, &proto, path),
|
||||
(false, true) => generate_server_streaming(method, &proto, path),
|
||||
(true, false) => generate_client_streaming(method, &proto, path),
|
||||
(true, true) => generate_streaming(method, &proto, path),
|
||||
};
|
||||
|
||||
stream.extend(method);
|
||||
}
|
||||
|
||||
stream
|
||||
}
|
||||
|
||||
fn generate_unary(method: &Method, proto: &str, path: String) -> TokenStream {
|
||||
let ident = format_ident!("{}", method.name);
|
||||
let request: Path = syn::parse_str(&format!("{}::{}", proto, method.input_type)).unwrap();
|
||||
let response: Path = syn::parse_str(&format!("{}::{}", proto, method.output_type)).unwrap();
|
||||
|
||||
quote! {
|
||||
pub async fn #ident (&mut self, request: tonic::Request<#request>)
|
||||
-> Result<tonic::Response<#response>, tonic::Status> {
|
||||
let codec = tonic::codec::ProstCodec::new();
|
||||
let path = http::uri::PathAndQuery::from_static(#path);
|
||||
self.inner.unary(request, path, codec).await
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_server_streaming(method: &Method, proto: &str, path: String) -> TokenStream {
|
||||
let ident = format_ident!("{}", method.name);
|
||||
let request: Path = syn::parse_str(&format!("{}::{}", proto, method.input_type)).unwrap();
|
||||
let response: Path = syn::parse_str(&format!("{}::{}", proto, method.output_type)).unwrap();
|
||||
|
||||
quote! {
|
||||
pub async fn #ident (&mut self, request: tonic::Request<#request>)
|
||||
-> Result<tonic::Response<tonic::codec::Streaming<#response>>, tonic::Status> {
|
||||
let codec = tonic::codec::ProstCodec::new();
|
||||
let path = http::uri::PathAndQuery::from_static(#path);
|
||||
self.inner.server_streaming(request, path, codec).await
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_client_streaming(method: &Method, proto: &str, path: String) -> TokenStream {
|
||||
let ident = format_ident!("{}", method.name);
|
||||
let request: Path = syn::parse_str(&format!("{}::{}", proto, method.input_type)).unwrap();
|
||||
let response: Path = syn::parse_str(&format!("{}::{}", proto, method.output_type)).unwrap();
|
||||
|
||||
quote! {
|
||||
pub async fn #ident <S>(&mut self, request: tonic::Request<S>)
|
||||
-> Result<tonic::Response<#response>, tonic::Status>
|
||||
where S: tonic::_codegen::Stream<Item = Result<#request, tonic::Status>> + Send + 'static,
|
||||
{
|
||||
let codec = tonic::codec::ProstCodec::new();
|
||||
let path = http::uri::PathAndQuery::from_static(#path);
|
||||
let request = request.map(|s| Box::pin(s));
|
||||
self.inner.client_streaming(request, path, codec).await
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_streaming(method: &Method, proto: &str, path: String) -> TokenStream {
|
||||
let ident = format_ident!("{}", method.name);
|
||||
let request: Path = syn::parse_str(&format!("{}::{}", proto, method.input_type)).unwrap();
|
||||
let response: Path = syn::parse_str(&format!("{}::{}", proto, method.output_type)).unwrap();
|
||||
|
||||
quote! {
|
||||
pub async fn #ident <S>(&mut self, request: tonic::Request<S>)
|
||||
-> Result<tonic::Response<tonic::codec::Streaming<#response>>, tonic::Status>
|
||||
where S: tonic::_codegen::Stream<Item = Result<#request, tonic::Status>> + Send + 'static,
|
||||
{
|
||||
let codec = tonic::codec::ProstCodec::new();
|
||||
let path = http::uri::PathAndQuery::from_static(#path);
|
||||
let request = request.map(|s| Box::pin(s));
|
||||
self.inner.streaming(request, path, codec).await
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,12 +3,44 @@
|
||||
|
||||
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! {
|
||||
pub struct #service_ident <T> {
|
||||
inner: tonic::client::Grpc<T>,
|
||||
}
|
||||
|
||||
impl<T> #service_ident <T>
|
||||
where T: tonic::GrpcService<tonic::body::BoxAsyncBody>,
|
||||
T::ResponseBody: tonic::body::Body + tonic::_codegen::HttpBody + Send + 'static,
|
||||
<T::ResponseBody as tonic::_codegen::HttpBody>::Error: Into<tonic::error::Error> + Send,
|
||||
<T::ResponseBody as tonic::_codegen::HttpBody>::Data: Send, {
|
||||
pub fn new(inner: T) -> Self {
|
||||
let inner = tonic::client::Grpc::new(inner);
|
||||
Self { inner }
|
||||
}
|
||||
|
||||
#methods
|
||||
}
|
||||
};
|
||||
|
||||
TokenStream::from(output)
|
||||
}
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn server(attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||
let mut original = item.clone();
|
||||
|
||||
@@ -272,7 +272,7 @@ fn generate_client_streaming(
|
||||
struct #service_ident(pub std::sync::Arc<#service_impl>);
|
||||
|
||||
impl<S> tonic::server::ClientStreamingService<S> for #service_ident
|
||||
where S: Stream<Item = Result<#request, Status>> + Unpin + Send + 'static {
|
||||
where S: tonic::_codegen::Stream<Item = Result<#request, Status>> + Unpin + Send + 'static {
|
||||
type Response = #response;
|
||||
type Future = BoxFuture<tonic::Response<Self::Response>, tonic::Status>;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user