Skip to content

Commit

Permalink
feat(ops): support `Result<impl Future<Output = Result<T, AnyError>> …
Browse files Browse the repository at this point in the history
…+ 'static, AnyError>` (denoland#14869)

feat(ops): support a result returning a future returning a result
  • Loading branch information
littledivy committed Jun 16, 2022
1 parent e7ea4ed commit 364da46
Showing 1 changed file with 61 additions and 30 deletions.
91 changes: 61 additions & 30 deletions ops/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,14 @@ pub fn op(attr: TokenStream, item: TokenStream) -> TokenStream {
let MacroArgs { is_unstable, is_v8 } = margs;
let func = syn::parse::<syn::ItemFn>(item).expect("expected a function");
let name = &func.sig.ident;
let generics = &func.sig.generics;
let mut generics = func.sig.generics.clone();
let scope_lifetime =
syn::LifetimeDef::new(syn::Lifetime::new("'scope", Span::call_site()));
if !generics.lifetimes().any(|def| *def == scope_lifetime) {
generics
.params
.push(syn::GenericParam::Lifetime(scope_lifetime));
}
let type_params = exclude_lifetime_params(&func.sig.generics.params);
let where_clause = &func.sig.generics.where_clause;

Expand Down Expand Up @@ -131,7 +138,7 @@ pub fn op(attr: TokenStream, item: TokenStream) -> TokenStream {
#original_func

pub fn v8_func #generics (
scope: &mut #core::v8::HandleScope,
scope: &mut #core::v8::HandleScope<'scope>,
args: #core::v8::FunctionCallbackArguments,
mut rv: #core::v8::ReturnValue,
) #where_clause {
Expand All @@ -145,32 +152,49 @@ pub fn op(attr: TokenStream, item: TokenStream) -> TokenStream {
fn codegen_v8_async(
core: &TokenStream2,
f: &syn::ItemFn,
_margs: MacroArgs,
margs: MacroArgs,
asyncness: bool,
) -> TokenStream2 {
let arg0 = f.sig.inputs.first();
let uses_opstate = arg0.map(is_rc_refcell_opstate).unwrap_or_default();
let args_head = if uses_opstate {
quote! { state, }
} else {
quote! {}
};
let rust_i0 = if uses_opstate { 1 } else { 0 };
let MacroArgs { is_v8, .. } = margs;
let special_args = f
.sig
.inputs
.iter()
.map_while(|a| {
(if is_v8 { scope_arg(a) } else { None }).or_else(|| opstate_arg(a))
})
.collect::<Vec<_>>();
let rust_i0 = special_args.len();
let args_head = special_args.into_iter().collect::<TokenStream2>();

let (arg_decls, args_tail) = codegen_args(core, f, rust_i0, 1);
let type_params = exclude_lifetime_params(&f.sig.generics.params);

let (pre_result, result_fut) = match asyncness {
let (pre_result, mut result_fut) = match asyncness {
true => (
quote! {},
quote! { Self::call::<#type_params>(#args_head #args_tail) },
quote! { Self::call::<#type_params>(#args_head #args_tail).await; },
),
false => (
quote! { let result_fut = Self::call::<#type_params>(#args_head #args_tail); },
quote! { result_fut },
quote! { result_fut.await; },
),
};
let result_wrapper = match is_result(&f.sig.output) {
true => quote! {},
true => {
// Support `Result<impl Future<Output = Result<T, AnyError>> + 'static, AnyError>`
if !asyncness {
result_fut = quote! { result_fut; };
quote! {
let result = match result {
Ok(fut) => fut.await,
Err(e) => return (promise_id, op_id, #core::_ops::to_op_result::<()>(get_class, Err(e))),
};
}
} else {
quote! {}
}
}
false => quote! { let result = Ok(result); },
};

Expand Down Expand Up @@ -209,34 +233,38 @@ fn codegen_v8_async(

#pre_result
#core::_ops::queue_async_op(scope, async move {
let result = #result_fut.await;
let result = #result_fut
#result_wrapper
(promise_id, op_id, #core::_ops::to_op_result(get_class, result))
});
}
}

fn scope_arg(arg: &FnArg) -> Option<TokenStream2> {
if is_handle_scope(arg) {
Some(quote! { scope, })
} else {
None
}
}

fn opstate_arg(arg: &FnArg) -> Option<TokenStream2> {
match arg {
arg if is_rc_refcell_opstate(arg) => Some(quote! { ctx.state.clone(), }),
arg if is_mut_ref_opstate(arg) => {
Some(quote! { &mut ctx.state.borrow_mut(), })
}
_ => None,
}
}

/// Generate the body of a v8 func for a sync op
fn codegen_v8_sync(
core: &TokenStream2,
f: &syn::ItemFn,
margs: MacroArgs,
) -> TokenStream2 {
let MacroArgs { is_v8, .. } = margs;
let scope_arg = |arg: &FnArg| {
if is_handle_scope(arg) {
Some(quote! { scope, })
} else {
None
}
};
let opstate_arg = |arg: &FnArg| match arg {
arg if is_rc_refcell_opstate(arg) => Some(quote! { ctx.state.clone(), }),
arg if is_mut_ref_opstate(arg) => {
Some(quote! { &mut ctx.state.borrow_mut(), })
}
_ => None,
};
let special_args = f
.sig
.inputs
Expand Down Expand Up @@ -386,6 +414,7 @@ fn is_unit_result(ty: impl ToTokens) -> bool {
fn is_mut_ref_opstate(arg: &syn::FnArg) -> bool {
tokens(arg).ends_with(": & mut OpState")
|| tokens(arg).ends_with(": & mut deno_core :: OpState")
|| tokens(arg).ends_with("mut OpState")
}

fn is_rc_refcell_opstate(arg: &syn::FnArg) -> bool {
Expand All @@ -398,6 +427,8 @@ fn is_handle_scope(arg: &syn::FnArg) -> bool {
|| tokens(arg).ends_with(": & mut v8 :: HandleScope < 'a >")
|| tokens(arg).ends_with(": & mut deno_core :: v8 :: HandleScope")
|| tokens(arg).ends_with(": & mut deno_core :: v8 :: HandleScope < 'a >")
|| tokens(arg).contains("mut v8 :: HandleScope")
|| tokens(arg).ends_with(": & mut v8 :: HandeScope < 'scope >")
}

fn is_future(ty: impl ToTokens) -> bool {
Expand Down

0 comments on commit 364da46

Please sign in to comment.