diff --git a/tonic-macros/src/lib.rs b/tonic-macros/src/lib.rs index 3da3720..eb65f52 100644 --- a/tonic-macros/src/lib.rs +++ b/tonic-macros/src/lib.rs @@ -15,118 +15,16 @@ pub fn server(attr: TokenStream, item: TokenStream) -> TokenStream { let item = syn::parse_macro_input!(item as ItemImpl); let args = syn::parse_macro_input!(attr as AttributeArgs); - let service = load_service(args); - let service_def = service::parse_service_impl(item, service); + let (service, proto_path) = load_service(args); + + let service_def = service::parse_service_impl(item, service, proto_path); let output = service::generate(service_def); original.extend(TokenStream::from(output)); original - - // let mut original = item.clone(); - // let ItemImpl { self_ty, items, .. } = syn::parse_macro_input!(item as ItemImpl); - - // let mut m_ident = None; - // for item in items { - // if let ImplItem::Method(method) = item { - // // println!("{:?}", method); - - // let ImplItemMethod { sig, .. } = method; - - // if sig.asyncness.is_some() { - // let name = format!("{}", sig.ident); - - // if let Some(_method) = service.methods.iter().find(|method| method.name == name) { - // // println!("found method!"); - // m_ident = Some(sig.ident.clone()); - // } - // } - // } - // } - - // let service_name = service.proto_name.clone(); - - // let ts = quote! { - // use tonic::_codegen; - // use proto::*; - - // #[derive(Clone)] - // pub struct GrpcServer { - // inner: std::sync::Arc<#s>, - // } - - // impl GrpcServer { - // fn new(t: #s) -> Self { - // Self { inner: std::sync::Arc::new(t) } - // } - // } - - // impl _codegen::Service<()> for GrpcServer { - // type Response = Self; - // type Error = tonic::error::Never; - // type Future = _codegen::Ready>; - - // fn poll_ready(&mut self, _cx: &mut _codegen::Context<'_>) -> _codegen::Poll> { - // std::task::Poll::Ready(Ok(())) - // } - - // fn call(&mut self, _: ()) -> Self::Future { - // _codegen::ok(self.clone()) - // } - // } - - // impl _codegen::Service<_codegen::http::Request> for GrpcServer { - // type Response = _codegen::http::Response; - // type Error = tonic::error::Never; - // type Future = _codegen::ResponseFuture2; - - // fn poll_ready(&mut self, _cx: &mut _codegen::Context<'_>) -> _codegen::Poll> { - // Ok(()).into() - // } - - // fn call(&mut self, request: _codegen::http::Request) -> Self::Future { - // let inner = self.inner.clone(); - - // match request.uri().path() { - // "/helloworld.Greeter/SayHello" => { - // use tonic::_codegen::*; - // use tonic::*; - - // pub struct SayHello(pub std::sync::Arc<#s>); - - // impl tonic::server::UnaryService for SayHello { - // type Response = HelloReply; - // type Future = Pin, Status>> + Send + 'static>>; - - // fn call(&mut self, request: Request) -> Self::Future { - // let inner = self.0.clone(); - // let fut = async move { - // inner.#m_ident(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, request).await; - // Ok(res) - // }; - - // Box::pin(fut) - // }, - // _ => unimplemented!("use grpc unimplemented") - // } - // } - // } - - // }; } -fn load_service(attr: AttributeArgs) -> Service { +fn load_service(attr: AttributeArgs) -> (Service, String) { use syn::{Lit, Meta, MetaNameValue, NestedMeta}; let service = attr @@ -147,14 +45,33 @@ fn load_service(attr: AttributeArgs) -> Service { 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(); - serde_json::from_str(&json).unwrap() + (svc, proto_path) } /// A service descriptor. diff --git a/tonic-macros/src/service.rs b/tonic-macros/src/service.rs index 1e894b3..40026db 100644 --- a/tonic-macros/src/service.rs +++ b/tonic-macros/src/service.rs @@ -9,10 +9,15 @@ pub struct ServiceDef { name_str: String, package: String, proto_name: String, + proto_path: String, methods: Vec<(Method, Ident)>, } -pub(crate) fn parse_service_impl(item: ItemImpl, mut service: Service) -> ServiceDef { +pub(crate) fn parse_service_impl( + item: ItemImpl, + mut service: Service, + proto_path: String, +) -> ServiceDef { let ItemImpl { self_ty, items, .. } = item; let name = if let Type::Path(t) = *self_ty { @@ -48,6 +53,7 @@ pub(crate) fn parse_service_impl(item: ItemImpl, mut service: Service) -> Servic name_str: service.name, package: service.package, proto_name: service.proto_name, + proto_path, methods, } } @@ -120,7 +126,12 @@ fn generate_methods(service: &ServiceDef) -> TokenStream { ); let method_path = Lit::Str(LitStr::new(&path, Span::call_site())); - let method_stream = generate_unary(method, ident.clone(), service.name.clone()); + let method_stream = generate_unary( + method, + ident.clone(), + service.name.clone(), + &service.proto_path, + ); let method = quote! { #method_path => { @@ -133,11 +144,17 @@ fn generate_methods(service: &ServiceDef) -> TokenStream { stream } -fn generate_unary(method: &Method, method_ident: Ident, service_impl: Path) -> TokenStream { +fn generate_unary( + 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!("hello_world::{}", method.input_type)).unwrap(); - let response: Path = syn::parse_str(&format!("hello_world::{}", method.output_type)).unwrap(); + let request: Path = syn::parse_str(&format!("{}::{}", proto_path, method.input_type)).unwrap(); + let response: Path = + syn::parse_str(&format!("{}::{}", proto_path, method.output_type)).unwrap(); quote! { struct #service_ident(pub std::sync::Arc<#service_impl>);