Skip to content

Commit

Permalink
Add helper macro for boxed futures
Browse files Browse the repository at this point in the history
  • Loading branch information
efoerster committed May 30, 2019
1 parent 5e4f8c5 commit b9c4428
Show file tree
Hide file tree
Showing 11 changed files with 229 additions and 143 deletions.
11 changes: 11 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Expand Up @@ -15,6 +15,7 @@ bytes = "0.4.12"
byteorder = "1"
clap = "2.33"
copy_dir = "0.1.2"
futures-boxed = { path = "futures_boxed" }
futures-preview = { version = "0.3.0-alpha.15", features = ["compat"] }
html2md = "0.2.9"
indoc = "0.3.1"
Expand Down
14 changes: 14 additions & 0 deletions futures_boxed/Cargo.toml
@@ -0,0 +1,14 @@
[package]
name = "futures-boxed"
version = "0.1.0"
authors = [
"Eric Förster <efoerster@users.noreply.github.com>",
"Patrick Förster <pfoerster@users.noreply.github.com>"]
edition = "2018"

[lib]
proc-macro = true

[dependencies]
syn = { version = "0.15", features = ["full"] }
quote = "0.6"
67 changes: 67 additions & 0 deletions futures_boxed/src/lib.rs
@@ -0,0 +1,67 @@
#![feature(async_await)]
#![recursion_limit = "128"]

extern crate proc_macro;

use proc_macro::TokenStream;
use quote::quote;
use quote::ToTokens;
use std::iter::FromIterator;
use syn::export::TokenStream2;
use syn::*;

#[proc_macro_attribute]
pub fn boxed(_attr: TokenStream, item: TokenStream) -> TokenStream {
match parse::<ItemFn>(item.clone()) {
Ok(fn_) => boxed_fn(fn_),
Err(_) => {
let item: TokenStream = TokenStream::from_iter(item.into_iter().skip(1));
let method: TraitItemMethod = parse(item).unwrap();
boxed_trait_method(method)
}
}
}

fn boxed_fn(fn_: ItemFn) -> TokenStream {
let attrs = &fn_.attrs;
let vis = &fn_.vis;
let decl = boxed_fn_decl(&fn_.decl, &fn_.constness, &fn_.ident);
let block = &fn_.block;
let tokens = quote! {
#(#attrs)*
#vis #decl {
let task = async move #block;
task.boxed()
}
};

tokens.into()
}

fn boxed_trait_method(method: TraitItemMethod) -> TokenStream {
let attrs = &method.attrs;
let decl = boxed_fn_decl(&method.sig.decl, &method.sig.constness, &method.sig.ident);
let tokens = quote! {
#(#attrs)*
#decl;
};

tokens.into()
}

fn boxed_fn_decl(
decl: &FnDecl,
constness: &Option<syn::token::Const>,
ident: &Ident,
) -> TokenStream2 {
let generics = &decl.generics;
let inputs = &decl.inputs;
let return_ty = match &decl.output {
ReturnType::Default => quote!(()),
ReturnType::Type(_, ty) => ty.into_token_stream(),
};

quote! {
#constness fn #ident #generics(#inputs) -> futures::future::BoxFuture<'_, #return_ty>
}
}
1 change: 1 addition & 0 deletions jsonrpc/Cargo.toml
Expand Up @@ -7,6 +7,7 @@ authors = [
edition = "2018"

[dependencies]
futures-boxed = { path = "../futures_boxed" }
futures-preview = { version = "0.3.0-alpha.15", features = ["compat"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
Expand Down
24 changes: 12 additions & 12 deletions jsonrpc/src/client.rs
Expand Up @@ -3,6 +3,7 @@ use futures::channel::oneshot;
use futures::future::BoxFuture;
use futures::lock::Mutex;
use futures::prelude::*;
use futures_boxed::boxed;
use serde::Serialize;
use serde_json::json;
use std::collections::HashMap;
Expand All @@ -14,7 +15,8 @@ pub type Result<T> = std::result::Result<T, Error>;
pub type FutureResult<'a, T> = BoxFuture<'a, Result<T>>;

pub trait ResponseHandler {
fn handle(&self, response: Response) -> BoxFuture<'_, ()>;
#[boxed]
async fn handle(&self, response: Response);
}

pub struct Client<O> {
Expand Down Expand Up @@ -69,19 +71,17 @@ impl<O> ResponseHandler for Client<O>
where
O: Output,
{
fn handle(&self, response: Response) -> BoxFuture<'_, ()> {
let task = async move {
let id = response.id.expect("Expected response with id");
let mut queue = self.queue.lock().await;
let sender = queue.remove(&id).expect("Unexpected response received");
#[boxed]
async fn handle(&self, response: Response) {
let id = response.id.expect("Expected response with id");
let mut queue = self.queue.lock().await;
let sender = queue.remove(&id).expect("Unexpected response received");

let result = match response.error {
Some(why) => Err(why),
None => Ok(response.result.unwrap_or(serde_json::Value::Null)),
};
sender.send(result).unwrap();
let result = match response.error {
Some(why) => Err(why),
None => Ok(response.result.unwrap_or(serde_json::Value::Null)),
};

task.boxed()
sender.send(result).unwrap();
}
}
8 changes: 5 additions & 3 deletions jsonrpc/src/server.rs
@@ -1,20 +1,22 @@
use crate::types::*;
use futures::future::BoxFuture;
use futures::prelude::*;
use futures_boxed::boxed;
use serde::de::DeserializeOwned;
use serde::Serialize;
use serde_json::json;

pub type Result<T> = std::result::Result<T, String>;

pub trait RequestHandler {
fn handle_request(&self, request: Request) -> BoxFuture<'_, Response>;
#[boxed]
async fn handle_request(&self, request: Request) -> Response;

fn handle_notification(&self, notification: Notification);
}

pub trait ActionHandler {
fn execute_actions(&self) -> BoxFuture<'_, ()>;
#[boxed]
async fn execute_actions(&self);
}

pub async fn handle_request<'a, H, F, I, O>(request: Request, handler: H) -> Response
Expand Down
1 change: 1 addition & 0 deletions jsonrpc_derive/Cargo.toml
Expand Up @@ -10,5 +10,6 @@ edition = "2018"
proc-macro = true

[dependencies]
futures-boxed = { path = "../futures_boxed" }
syn = { version = "0.15", features = ["full"] }
quote = "0.6"
18 changes: 7 additions & 11 deletions jsonrpc_derive/src/lib.rs
Expand Up @@ -73,21 +73,17 @@ pub fn jsonrpc_server(
#impl_

impl #generics jsonrpc::RequestHandler for #self_ty {
fn handle_request(&self, request: jsonrpc::Request)
-> futures::future::BoxFuture<'_, jsonrpc::Response> {
#[boxed]
async fn handle_request(&self, request: jsonrpc::Request) -> jsonrpc::Response {
use futures::prelude::*;
use jsonrpc::*;

let handler = async move {
match request.method.as_str() {
#(#requests),*,
_ => {
Response::error(Error::method_not_found_error(), Some(request.id))
}
match request.method.as_str() {
#(#requests),*,
_ => {
Response::error(Error::method_not_found_error(), Some(request.id))
}
};

handler.boxed()
}
}

fn handle_notification(&self, notification: jsonrpc::Notification) {
Expand Down
51 changes: 23 additions & 28 deletions src/client.rs
Expand Up @@ -2,7 +2,8 @@ use crate::formatting::bibtex::BibtexFormattingOptions;
use futures::future::BoxFuture;
use futures::lock::Mutex;
use futures::prelude::*;
use jsonrpc::client::FutureResult;
use futures_boxed::boxed;
use jsonrpc::client::{FutureResult, Result};
use jsonrpc_derive::{jsonrpc_client, jsonrpc_method};
use lsp_types::*;
use std::borrow::Cow;
Expand Down Expand Up @@ -34,38 +35,32 @@ pub struct LspClientMock {
}

impl LspClient for LspClientMock {
fn configuration(&self, params: ConfigurationParams) -> FutureResult<'_, serde_json::Value> {
let handler = async move {
let options = self.options.lock().await;
match params.items[0].section {
Some(Cow::Borrowed("bibtex.formatting")) => options
.bibtex_formatting
.as_ref()
.map(|options| serde_json::to_value(vec![options]).unwrap())
.ok_or(jsonrpc::Error::internal_error("Internal error".to_owned())),
_ => {
unreachable!();
}
#[boxed]
async fn configuration(&self, params: ConfigurationParams) -> Result<serde_json::Value> {
let options = self.options.lock().await;
match params.items[0].section {
Some(Cow::Borrowed("bibtex.formatting")) => options
.bibtex_formatting
.as_ref()
.map(|options| serde_json::to_value(vec![options]).unwrap())
.ok_or(jsonrpc::Error::internal_error("Internal error".to_owned())),
_ => {
unreachable!();
}
};
handler.boxed()
}
}

fn show_message(&self, params: ShowMessageParams) -> BoxFuture<'_, ()> {
let handler = async move {
let mut messages = self.messages.lock().await;
messages.push(params);
};
handler.boxed()
#[boxed]
async fn show_message(&self, params: ShowMessageParams) {
let mut messages = self.messages.lock().await;
messages.push(params);
}

fn register_capability(&self, _params: RegistrationParams) -> FutureResult<'_, ()> {
let handler = async move { Ok(()) };
handler.boxed()
#[boxed]
async fn register_capability(&self, _params: RegistrationParams) -> Result<()> {
Ok(())
}

fn publish_diagnostics(&self, _params: PublishDiagnosticsParams) -> BoxFuture<'_, ()> {
let handler = async move {};
handler.boxed()
}
#[boxed]
async fn publish_diagnostics(&self, _params: PublishDiagnosticsParams) {}
}

0 comments on commit b9c4428

Please sign in to comment.