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 | |
parent | 58aa1ac09b1d9e4769d0a0661cf12e2b2db41b14 (diff) |
CTAN sync 202105230300
Diffstat (limited to 'support/texlab/crates')
-rw-r--r-- | support/texlab/crates/jsonrpc/Cargo.toml | 20 | ||||
-rw-r--r-- | support/texlab/crates/jsonrpc/src/client.rs | 77 | ||||
-rw-r--r-- | support/texlab/crates/jsonrpc/src/lib.rs | 67 | ||||
-rw-r--r-- | support/texlab/crates/jsonrpc/src/server.rs | 131 | ||||
-rw-r--r-- | support/texlab/crates/jsonrpc/src/types.rs | 144 | ||||
-rw-r--r-- | support/texlab/crates/jsonrpc_derive/Cargo.toml | 15 | ||||
-rw-r--r-- | support/texlab/crates/jsonrpc_derive/src/lib.rs | 207 |
7 files changed, 0 insertions, 661 deletions
diff --git a/support/texlab/crates/jsonrpc/Cargo.toml b/support/texlab/crates/jsonrpc/Cargo.toml deleted file mode 100644 index c5cec72074..0000000000 --- a/support/texlab/crates/jsonrpc/Cargo.toml +++ /dev/null @@ -1,20 +0,0 @@ -[package] -name = "jsonrpc" -version = "0.1.0" -authors = [ - "Eric Förster <eric.foerster@outlook.com>", - "Patrick Förster <patrick.foerster@outlook.de>"] -edition = "2018" - -[lib] -doctest = false - -[dependencies] -async-trait = "0.1" -chashmap = "2.2" -futures = "0.3" -log = "0.4" -serde = { version = "1.0", features = ["derive", "rc"] } -serde_json = "1.0" -serde_repr = "0.1" -tokio = { version = "0.2", features = ["rt-core"] } diff --git a/support/texlab/crates/jsonrpc/src/client.rs b/support/texlab/crates/jsonrpc/src/client.rs deleted file mode 100644 index 7d714283c6..0000000000 --- a/support/texlab/crates/jsonrpc/src/client.rs +++ /dev/null @@ -1,77 +0,0 @@ -use super::types::*; -use async_trait::async_trait; -use chashmap::CHashMap; -use futures::{ - channel::{mpsc, oneshot}, - prelude::*, -}; -use serde::Serialize; -use serde_json::json; -use std::sync::atomic::{AtomicU64, Ordering}; - -pub type Result<T> = std::result::Result<T, Error>; - -#[async_trait] -pub trait ResponseHandler { - async fn handle(&self, response: Response); -} - -#[derive(Debug)] -pub struct Client { - output: mpsc::Sender<String>, - request_id: AtomicU64, - senders_by_id: CHashMap<Id, oneshot::Sender<Result<serde_json::Value>>>, -} - -impl Client { - pub fn new(output: mpsc::Sender<String>) -> Self { - Self { - output, - request_id: AtomicU64::new(0), - senders_by_id: CHashMap::new(), - } - } - - pub async fn send_request<T: Serialize>( - &self, - method: String, - params: T, - ) -> Result<serde_json::Value> { - let id = self.request_id.fetch_add(1, Ordering::SeqCst); - let request = Request::new(method, json!(params), Id::Number(id)); - - let (result_tx, result_rx) = oneshot::channel(); - self.senders_by_id.insert(request.id.clone(), result_tx); - self.send(Message::Request(request)).await; - - result_rx.await.unwrap() - } - - pub async fn send_notification<T: Serialize>(&self, method: String, params: T) { - let notification = Notification::new(method, json!(params)); - self.send(Message::Notification(notification)).await; - } - - async fn send(&self, message: Message) { - let mut output = self.output.clone(); - let json = serde_json::to_string(&message).unwrap(); - output.send(json).await.unwrap(); - } -} - -#[async_trait] -impl ResponseHandler for Client { - async fn handle(&self, response: Response) { - let id = response.id.expect("Expected response with id"); - let result = match response.error { - Some(why) => Err(why), - None => Ok(response.result.unwrap_or(serde_json::Value::Null)), - }; - - let result_tx = self - .senders_by_id - .remove(&id) - .expect("Unexpected response received"); - result_tx.send(result).unwrap(); - } -} diff --git a/support/texlab/crates/jsonrpc/src/lib.rs b/support/texlab/crates/jsonrpc/src/lib.rs deleted file mode 100644 index 3a771e6ba5..0000000000 --- a/support/texlab/crates/jsonrpc/src/lib.rs +++ /dev/null @@ -1,67 +0,0 @@ -pub mod client; -pub mod server; -mod types; - -pub use self::{ - client::{Client, ResponseHandler}, - server::{handle_notification, handle_request, Middleware, RequestHandler}, - types::*, -}; - -use futures::{channel::mpsc, prelude::*}; -use log::error; -use std::sync::Arc; - -#[derive(Debug)] -pub struct MessageHandler<S, C> { - pub server: Arc<S>, - pub client: Arc<C>, - pub output: mpsc::Sender<String>, -} - -impl<S, C> MessageHandler<S, C> -where - S: RequestHandler + Middleware + Send + Sync + 'static, - C: ResponseHandler + Send + Sync + 'static, -{ - pub async fn handle(&mut self, json: &str) { - self.server.before_message().await; - - match serde_json::from_str(json).map_err(|_| Error::parse_error()) { - Ok(Message::Request(request)) => { - let server = Arc::clone(&self.server); - let mut output = self.output.clone(); - tokio::spawn(async move { - let response = server.handle_request(request).await; - if let Some(error) = response.error.as_ref() { - error!("{:?}", error); - } - let json = serde_json::to_string(&response).unwrap(); - output.send(json).await.unwrap(); - server.after_message().await; - }); - } - Ok(Message::Notification(notification)) => { - self.server.handle_notification(notification).await; - self.after_message(); - } - Ok(Message::Response(response)) => { - self.client.handle(response).await; - self.after_message(); - } - Err(why) => { - let response = Response::error(why, None); - let json = serde_json::to_string(&response).unwrap(); - self.output.send(json).await.unwrap(); - self.after_message(); - } - }; - } - - fn after_message(&self) { - let server = Arc::clone(&self.server); - tokio::spawn(async move { - server.after_message().await; - }); - } -} diff --git a/support/texlab/crates/jsonrpc/src/server.rs b/support/texlab/crates/jsonrpc/src/server.rs deleted file mode 100644 index ce34dc8b60..0000000000 --- a/support/texlab/crates/jsonrpc/src/server.rs +++ /dev/null @@ -1,131 +0,0 @@ -use super::types::*; -use async_trait::async_trait; -use futures::prelude::*; -use serde::{de::DeserializeOwned, Serialize}; -use serde_json::json; - -pub type Result<T> = std::result::Result<T, String>; - -#[async_trait] -pub trait RequestHandler { - async fn handle_request(&self, request: Request) -> Response; - - async fn handle_notification(&self, notification: Notification); -} - -#[async_trait] -pub trait Middleware { - async fn before_message(&self); - - async fn after_message(&self); -} - -pub async fn handle_request<'a, H, F, I, O>(request: Request, handler: H) -> Response -where - H: Fn(I) -> F + Send + Sync + 'a, - F: Future<Output = Result<O>> + Send, - I: DeserializeOwned + Send, - O: Serialize, -{ - let handle = |json| async move { - let params: I = serde_json::from_value(json).map_err(|_| Error::deserialize_error())?; - let result = handler(params).await.map_err(Error::internal_error)?; - Ok(result) - }; - - match handle(request.params).await { - Ok(result) => Response::result(json!(result), request.id), - Err(error) => Response::error(error, Some(request.id)), - } -} - -pub async fn handle_notification<'a, H, F, I>(notification: Notification, handler: H) -where - H: Fn(I) -> F + Send + Sync + 'a, - F: Future<Output = ()> + Send, - I: DeserializeOwned + Send, -{ - let error = Error::deserialize_error().message; - let params = serde_json::from_value(notification.params).expect(&error); - handler(params).await; -} - -#[cfg(test)] -mod tests { - use super::*; - - const METHOD_NAME: &str = "foo"; - - async fn increment(i: i32) -> Result<i32> { - Ok(i + 1) - } - - async fn panic(_params: ()) { - panic!("success"); - } - - fn setup_request<T: Serialize>(value: T) -> Request { - Request { - jsonrpc: PROTOCOL_VERSION.to_owned(), - params: json!(value), - method: METHOD_NAME.to_owned(), - id: Id::Number(0), - } - } - - fn setup_notification() -> Notification { - Notification { - jsonrpc: PROTOCOL_VERSION.to_owned(), - method: METHOD_NAME.to_owned(), - params: json!(()), - } - } - - #[tokio::test] - async fn request_valid() { - let value = 42; - let request = setup_request(value); - - let response = handle_request(request.clone(), increment).await; - let expected = Response { - jsonrpc: request.jsonrpc, - result: Some(json!(increment(value).await.unwrap())), - error: None, - id: Some(request.id), - }; - - assert_eq!(response, expected); - } - - #[tokio::test] - async fn request_invalid_params() { - let request = setup_request((0, 0)); - - let response = handle_request(request.clone(), increment).await; - let expected = Response { - jsonrpc: request.jsonrpc.clone(), - result: None, - error: Some(Error::deserialize_error()), - id: Some(request.id), - }; - - assert_eq!(response, expected); - } - - #[tokio::test] - #[should_panic(expected = "success")] - async fn notification_valid() { - let notification = setup_notification(); - handle_notification(notification, panic).await; - } - - #[tokio::test] - #[should_panic] - async fn notification_invalid_params() { - let notification = Notification { - params: json!(0), - ..setup_notification() - }; - handle_notification(notification, panic).await; - } -} diff --git a/support/texlab/crates/jsonrpc/src/types.rs b/support/texlab/crates/jsonrpc/src/types.rs deleted file mode 100644 index 30036d1c7f..0000000000 --- a/support/texlab/crates/jsonrpc/src/types.rs +++ /dev/null @@ -1,144 +0,0 @@ -use serde::{Deserialize, Serialize}; -use serde_repr::*; - -pub const PROTOCOL_VERSION: &str = "2.0"; - -#[derive(Debug, Eq, Hash, PartialEq, Clone, Deserialize, Serialize)] -#[serde(untagged)] -pub enum Id { - Number(u64), - String(String), -} - -#[derive(Clone, Copy, Debug, Eq, PartialEq, Deserialize_repr, Serialize_repr)] -#[repr(i32)] -pub enum ErrorCode { - ParseError = -32700, - InvalidRequest = -32600, - MethodNotFound = -32601, - InvalidParams = -32602, - InternalError = -32603, - ServerNotInitialized = -32002, - UnknownErrorCode = -32001, - RequestCancelled = -32800, -} - -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] -pub struct Error { - pub code: ErrorCode, - pub message: String, - - #[serde(skip_serializing_if = "Option::is_none")] - pub data: Option<serde_json::Value>, -} - -impl Error { - pub fn parse_error() -> Self { - Self { - code: ErrorCode::ParseError, - message: "Could not parse the input".to_owned(), - data: None, - } - } - - pub fn method_not_found_error() -> Self { - Self { - code: ErrorCode::MethodNotFound, - message: "Method not found".to_owned(), - data: None, - } - } - - pub fn deserialize_error() -> Self { - Self { - code: ErrorCode::InvalidParams, - message: "Could not deserialize parameter object".to_owned(), - data: None, - } - } - - pub fn internal_error(message: String) -> Self { - Self { - code: ErrorCode::InternalError, - message, - data: None, - } - } -} - -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] -pub struct Request { - pub jsonrpc: String, - pub method: String, - pub params: serde_json::Value, - pub id: Id, -} - -impl Request { - pub fn new(method: String, params: serde_json::Value, id: Id) -> Self { - Self { - jsonrpc: PROTOCOL_VERSION.to_owned(), - method, - params, - id, - } - } -} - -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] -pub struct Response { - pub jsonrpc: String, - - #[serde(skip_serializing_if = "Option::is_none")] - pub result: Option<serde_json::Value>, - - #[serde(skip_serializing_if = "Option::is_none")] - pub error: Option<Error>, - - pub id: Option<Id>, -} - -impl Response { - pub fn result(result: serde_json::Value, id: Id) -> Self { - Self { - jsonrpc: PROTOCOL_VERSION.to_owned(), - result: Some(result), - error: None, - id: Some(id), - } - } - - pub fn error(error: Error, id: Option<Id>) -> Self { - Self { - jsonrpc: PROTOCOL_VERSION.to_owned(), - result: None, - error: Some(error), - id, - } - } -} - -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] -pub struct Notification { - pub jsonrpc: String, - pub method: String, - pub params: serde_json::Value, -} - -impl Notification { - pub fn new(method: String, params: serde_json::Value) -> Self { - Self { - jsonrpc: PROTOCOL_VERSION.to_owned(), - method, - params, - } - } -} - -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] -#[serde(untagged)] -pub enum Message { - Request(Request), - Notification(Notification), - Response(Response), -} diff --git a/support/texlab/crates/jsonrpc_derive/Cargo.toml b/support/texlab/crates/jsonrpc_derive/Cargo.toml deleted file mode 100644 index fb99f16a26..0000000000 --- a/support/texlab/crates/jsonrpc_derive/Cargo.toml +++ /dev/null @@ -1,15 +0,0 @@ -[package] -name = "jsonrpc-derive" -version = "0.1.0" -authors = [ - "Eric Förster <eric.foerster@outlook.com>", - "Patrick Förster <patrick.foerster@outlook.de>"] -edition = "2018" - -[lib] -proc-macro = true -doctest = false - -[dependencies] -syn = "1.0" -quote = "1.0" 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 -} |