Inital commit
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
/target
|
||||
**/*.rs.bk
|
||||
Cargo.lock
|
||||
@@ -0,0 +1,5 @@
|
||||
[workspace]
|
||||
members = [
|
||||
"tonic",
|
||||
"tonic-macros"
|
||||
]
|
||||
@@ -0,0 +1 @@
|
||||
nightly-2019-08-09
|
||||
@@ -0,0 +1,19 @@
|
||||
[package]
|
||||
name = "tonic-macros"
|
||||
version = "0.1.0"
|
||||
authors = ["Lucio Franco <luciofranco14@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
tonic = { path = "../tonic" }
|
||||
syn = { version = "0.15", features = ["full"] }
|
||||
quote = "0.6"
|
||||
proc-macro2 = "0.4"
|
||||
prost-build = "0.5"
|
||||
tower-service = { git = "https://github.com/tower-rs/tower", branch = "std-future" }
|
||||
|
||||
[dev-dependencies]
|
||||
tokio = "=0.2.0-alpha.1"
|
||||
@@ -0,0 +1,98 @@
|
||||
#![feature(async_await)]
|
||||
|
||||
extern crate proc_macro;
|
||||
use proc_macro::TokenStream;
|
||||
use prost_build::{Comments, Method, Service};
|
||||
use quote::quote;
|
||||
use syn::{ImplItem, ImplItemMethod, ItemImpl, Type};
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn grpc(attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||
let service = load_service(attr);
|
||||
let mut original = item.clone();
|
||||
let ItemImpl { self_ty, items, .. } = syn::parse_macro_input!(item as ItemImpl);
|
||||
|
||||
let s = if let Type::Path(t) = *self_ty {
|
||||
t.path.segments.iter().next().unwrap().clone()
|
||||
} else {
|
||||
panic!("wrong type!")
|
||||
};
|
||||
|
||||
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 ts = quote! {
|
||||
// impl<'a> tower_service::Service<tonic::Request<()>> for #s {
|
||||
// type Response = tonic::Response<()>;
|
||||
// type Error = tonic::Status;
|
||||
// type Future = tonic::ResponseFuture<'a, Self::Response, Self::Error>;
|
||||
|
||||
// fn poll_ready(&mut self, _cx: &mut std::task::Context<'_>) -> std::task::Poll<Result<(), Self::Error>> {
|
||||
// std::task::Poll::Ready(Ok(()))
|
||||
// }
|
||||
|
||||
// fn call(&mut self, request: tonic::Request<()>) -> Self::Future {
|
||||
// Box::pin(self.#m_ident(request))
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
|
||||
let ts = quote! {
|
||||
impl tonic::GrpcInnerService<tonic::Request<()>> for #s {
|
||||
type Response = tonic::Response<()>;
|
||||
|
||||
fn call<'a>(&'a mut self, request: tonic::Request<()>) -> tonic::ResponseFuture<'a, Self::Response>
|
||||
where Self: 'a {
|
||||
Box::pin(self.#m_ident(request))
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
original.extend(TokenStream::from(ts));
|
||||
original
|
||||
}
|
||||
|
||||
fn load_service(_attr: TokenStream) -> Service {
|
||||
Service {
|
||||
name: "Greeter".into(),
|
||||
proto_name: "greeter".into(),
|
||||
package: "helloworld".into(),
|
||||
comments: Comments {
|
||||
leading_detached: Vec::new(),
|
||||
leading: Vec::new(),
|
||||
trailing: Vec::new(),
|
||||
},
|
||||
methods: vec![Method {
|
||||
name: "say_hello".into(),
|
||||
proto_name: "SayHello".into(),
|
||||
comments: Comments {
|
||||
leading_detached: Vec::new(),
|
||||
leading: Vec::new(),
|
||||
trailing: Vec::new(),
|
||||
},
|
||||
input_type: "HelloRequest".into(),
|
||||
output_type: "HelloResponse".into(),
|
||||
input_proto_type: "HelloRequest".into(),
|
||||
output_proto_type: "HelloResponse".into(),
|
||||
options: Default::default(),
|
||||
client_streaming: false,
|
||||
server_streaming: false,
|
||||
}],
|
||||
options: Default::default(),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
#![feature(async_await)]
|
||||
|
||||
use tonic::{Request, Response, Status};
|
||||
use tonic_macros::grpc;
|
||||
use tokio::timer::Delay;
|
||||
use std::time::Duration;
|
||||
|
||||
// #[derive(Debug)]
|
||||
// struct HelloRequest;
|
||||
// #[derive(Debug)]
|
||||
// struct HelloResponse;
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
struct MyGreeter {
|
||||
data: String,
|
||||
}
|
||||
|
||||
#[grpc(service = "proto/helloworld.proto")]
|
||||
impl MyGreeter {
|
||||
pub async fn say_hello(&mut self, request: Request<()>) -> Result<Response<()>, Status> {
|
||||
println!("Got a request: {:?}", request);
|
||||
|
||||
let string = &self.data;
|
||||
|
||||
let when = tokio::clock::now() + Duration::from_millis(100);
|
||||
Delay::new(when).await;
|
||||
|
||||
println!("My data: {:?}", string);
|
||||
|
||||
Delay::new(when).await;
|
||||
|
||||
Ok(Response::new(()))
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn grpc() {
|
||||
let mut greeter = MyGreeter { data: "some data".into()};
|
||||
|
||||
use tonic::GrpcInnerService;
|
||||
greeter.call(Request::new(())).await.unwrap();
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
[package]
|
||||
name = "tonic"
|
||||
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
|
||||
|
||||
[dependencies]
|
||||
tower-grpc = { git = "https://github.com/tower-rs/tower-grpc", branch = "std-future" }
|
||||
@@ -0,0 +1,14 @@
|
||||
pub use tower_grpc::*;
|
||||
|
||||
use std::future::Future;
|
||||
use std::pin::Pin;
|
||||
|
||||
pub type ResponseFuture<'a, T> = Pin<Box<dyn Future<Output = Result<T, Status>> + Send + 'a>>;
|
||||
|
||||
pub trait GrpcInnerService<Request> {
|
||||
type Response;
|
||||
|
||||
fn call<'a>(&'a mut self, request: Request) -> ResponseFuture<'a, Self::Response>
|
||||
where
|
||||
Self: 'a;
|
||||
}
|
||||
Reference in New Issue
Block a user