diff options
author | Norbert Preining <norbert@preining.info> | 2021-05-23 03:00:39 +0000 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2021-05-23 03:00:39 +0000 |
commit | f1261b349e875b842745b63258c3e338cb1fe3bf (patch) | |
tree | b5d402b3e80818cde2c079a42249f3dcb9732247 /support/texlab/crates/jsonrpc_derive/src/lib.rs | |
parent | 58aa1ac09b1d9e4769d0a0661cf12e2b2db41b14 (diff) |
CTAN sync 202105230300
Diffstat (limited to 'support/texlab/crates/jsonrpc_derive/src/lib.rs')
-rw-r--r-- | support/texlab/crates/jsonrpc_derive/src/lib.rs | 207 |
1 files changed, 0 insertions, 207 deletions
diff --git a/support/texlab/crates/jsonrpc_derive/src/lib.rs b/support/texlab/crates/jsonrpc_derive/src/lib.rs deleted file mode 100644 index 283be858db..0000000000 --- a/support/texlab/crates/jsonrpc_derive/src/lib.rs +++ /dev/null @@ -1,207 +0,0 @@ -#![recursion_limit = "128"] - -extern crate proc_macro; - -use proc_macro::TokenStream; -use quote::quote; -use syn::{export::TokenStream2, *}; - -macro_rules! unwrap { - ($input:expr, $arm:pat => $value:expr) => {{ - match $input { - $arm => $value, - _ => panic!(), - } - }}; -} - -enum MethodKind { - Request, - Notification, -} - -struct MethodMeta { - pub name: String, - pub kind: MethodKind, -} - -impl MethodMeta { - pub fn parse(attr: &Attribute) -> Self { - let meta = attr.parse_meta().unwrap(); - if meta.path().get_ident().unwrap() != "jsonrpc_method" { - panic!("Expected jsonrpc_method attribute"); - } - - let nested = unwrap!(meta, Meta::List(x) => x.nested); - let name = unwrap!(&nested[0], NestedMeta::Lit(Lit::Str(x)) => x.value()); - let kind = { - let lit = unwrap!(&nested[1], NestedMeta::Meta(Meta::NameValue(x)) => &x.lit); - let kind = unwrap!(lit, Lit::Str(x) => x.value()); - match kind.as_str() { - "request" => MethodKind::Request, - "notification" => MethodKind::Notification, - _ => panic!( - "Invalid method kind. Valid options are \"request\" and \"notification\"" - ), - } - }; - - Self { name, kind } - } -} - -#[proc_macro_attribute] -pub fn jsonrpc_method(_attr: TokenStream, item: TokenStream) -> TokenStream { - item -} - -#[proc_macro_attribute] -pub fn jsonrpc_server(_attr: TokenStream, item: TokenStream) -> TokenStream { - let impl_: ItemImpl = parse_macro_input!(item); - let generics = &impl_.generics; - let self_ty = &impl_.self_ty; - let (requests, notifications) = generate_server_skeletons(&impl_.items); - - let tokens = quote! { - #impl_ - - #[async_trait::async_trait] - impl #generics jsonrpc::RequestHandler for #self_ty { - async fn handle_request(&self, request: jsonrpc::Request) -> jsonrpc::Response { - use jsonrpc::*; - - match request.method.as_str() { - #(#requests),*, - _ => { - Response::error(Error::method_not_found_error(), Some(request.id)) - } - } - } - - async fn handle_notification(&self, notification: jsonrpc::Notification) { - match notification.method.as_str() { - #(#notifications),*, - _ => log::warn!("{}: {}", "Method not found", notification.method), - } - } - } - }; - - tokens.into() -} - -#[proc_macro_attribute] -pub fn jsonrpc_client(attr: TokenStream, item: TokenStream) -> TokenStream { - let trait_: ItemTrait = parse_macro_input!(item); - let trait_ident = &trait_.ident; - let stubs = generate_client_stubs(&trait_.items); - let attr: AttributeArgs = parse_macro_input!(attr); - let struct_ident = unwrap!(attr.first().unwrap(), NestedMeta::Meta(Meta::Path(x)) => x); - - let tokens = quote! { - #[async_trait::async_trait] - #trait_ - - pub struct #struct_ident { - client: jsonrpc::Client - } - - impl #struct_ident - { - pub fn new(output: futures::channel::mpsc::Sender<String>) -> Self { - Self { - client: jsonrpc::Client::new(output), - } - } - } - - #[async_trait::async_trait] - impl #trait_ident for #struct_ident - { - #(#stubs)* - } - - #[async_trait::async_trait] - impl jsonrpc::ResponseHandler for #struct_ident - { - async fn handle(&self, response: jsonrpc::Response) -> () { - self.client.handle(response).await - } - } - }; - - tokens.into() -} - -fn generate_server_skeletons(items: &Vec<ImplItem>) -> (Vec<TokenStream2>, Vec<TokenStream2>) { - let mut requests = Vec::new(); - let mut notifications = Vec::new(); - for item in items { - let method = unwrap!(item, ImplItem::Method(x) => x); - if method.attrs.is_empty() { - continue; - } - - let ident = &method.sig.ident; - let param_ty = unwrap!(&method.sig.inputs[1], FnArg::Typed(x) => &x.ty); - let meta = MethodMeta::parse(method.attrs.first().unwrap()); - let name = &meta.name.as_str(); - - match meta.kind { - MethodKind::Request => { - requests.push(quote!( - #name => { - let handler = |param: #param_ty| async move { - self.#ident(param).await - }; - - jsonrpc::handle_request(request, handler).await - } - )); - } - MethodKind::Notification => { - notifications.push(quote!( - #name => { - let handler = |param: #param_ty| async move { - self.#ident(param).await; - }; - - jsonrpc::handle_notification(notification, handler).await; - } - )); - } - } - } - - (requests, notifications) -} - -fn generate_client_stubs(items: &Vec<TraitItem>) -> Vec<TokenStream2> { - let mut stubs = Vec::new(); - for item in items { - let method = unwrap!(item, TraitItem::Method(x) => x); - let attrs = &method.attrs; - let sig = &method.sig; - let param = unwrap!(&sig.inputs[1], FnArg::Typed(x) => &x.pat); - let meta = MethodMeta::parse(attrs.first().unwrap()); - let name = &meta.name; - - let stub = match meta.kind { - MethodKind::Request => quote!( - #sig { - let result = self.client.send_request(#name.to_owned(), #param).await?; - serde_json::from_value(result).map_err(|_| jsonrpc::Error::deserialize_error()) - } - ), - MethodKind::Notification => quote!( - #sig { - self.client.send_notification(#name.to_owned(), #param).await - } - ), - }; - - stubs.push(stub); - } - - stubs -} |