1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-11-28 16:20:57 -05:00

feat(ops): support Result<impl Future<Output = Result<T, AnyError>> + 'static, AnyError> (#14869)

feat(ops): support a result returning a future returning a result
This commit is contained in:
Divy Srivastava 2022-06-16 20:34:55 +05:30 committed by GitHub
parent e7ea4edc8a
commit 364da468d2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -73,7 +73,14 @@ pub fn op(attr: TokenStream, item: TokenStream) -> TokenStream {
let MacroArgs { is_unstable, is_v8 } = margs; let MacroArgs { is_unstable, is_v8 } = margs;
let func = syn::parse::<syn::ItemFn>(item).expect("expected a function"); let func = syn::parse::<syn::ItemFn>(item).expect("expected a function");
let name = &func.sig.ident; 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 type_params = exclude_lifetime_params(&func.sig.generics.params);
let where_clause = &func.sig.generics.where_clause; let where_clause = &func.sig.generics.where_clause;
@ -131,7 +138,7 @@ pub fn op(attr: TokenStream, item: TokenStream) -> TokenStream {
#original_func #original_func
pub fn v8_func #generics ( pub fn v8_func #generics (
scope: &mut #core::v8::HandleScope, scope: &mut #core::v8::HandleScope<'scope>,
args: #core::v8::FunctionCallbackArguments, args: #core::v8::FunctionCallbackArguments,
mut rv: #core::v8::ReturnValue, mut rv: #core::v8::ReturnValue,
) #where_clause { ) #where_clause {
@ -145,32 +152,49 @@ pub fn op(attr: TokenStream, item: TokenStream) -> TokenStream {
fn codegen_v8_async( fn codegen_v8_async(
core: &TokenStream2, core: &TokenStream2,
f: &syn::ItemFn, f: &syn::ItemFn,
_margs: MacroArgs, margs: MacroArgs,
asyncness: bool, asyncness: bool,
) -> TokenStream2 { ) -> TokenStream2 {
let arg0 = f.sig.inputs.first(); let MacroArgs { is_v8, .. } = margs;
let uses_opstate = arg0.map(is_rc_refcell_opstate).unwrap_or_default(); let special_args = f
let args_head = if uses_opstate { .sig
quote! { state, } .inputs
} else { .iter()
quote! {} .map_while(|a| {
}; (if is_v8 { scope_arg(a) } else { None }).or_else(|| opstate_arg(a))
let rust_i0 = if uses_opstate { 1 } else { 0 }; })
.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 (arg_decls, args_tail) = codegen_args(core, f, rust_i0, 1);
let type_params = exclude_lifetime_params(&f.sig.generics.params); 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 => ( true => (
quote! {}, quote! {},
quote! { Self::call::<#type_params>(#args_head #args_tail) }, quote! { Self::call::<#type_params>(#args_head #args_tail).await; },
), ),
false => ( false => (
quote! { let result_fut = Self::call::<#type_params>(#args_head #args_tail); }, 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) { 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); }, false => quote! { let result = Ok(result); },
}; };
@ -209,13 +233,31 @@ fn codegen_v8_async(
#pre_result #pre_result
#core::_ops::queue_async_op(scope, async move { #core::_ops::queue_async_op(scope, async move {
let result = #result_fut.await; let result = #result_fut
#result_wrapper #result_wrapper
(promise_id, op_id, #core::_ops::to_op_result(get_class, result)) (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 /// Generate the body of a v8 func for a sync op
fn codegen_v8_sync( fn codegen_v8_sync(
core: &TokenStream2, core: &TokenStream2,
@ -223,20 +265,6 @@ fn codegen_v8_sync(
margs: MacroArgs, margs: MacroArgs,
) -> TokenStream2 { ) -> TokenStream2 {
let MacroArgs { is_v8, .. } = margs; 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 let special_args = f
.sig .sig
.inputs .inputs
@ -386,6 +414,7 @@ fn is_unit_result(ty: impl ToTokens) -> bool {
fn is_mut_ref_opstate(arg: &syn::FnArg) -> bool { fn is_mut_ref_opstate(arg: &syn::FnArg) -> bool {
tokens(arg).ends_with(": & mut OpState") tokens(arg).ends_with(": & mut OpState")
|| tokens(arg).ends_with(": & mut deno_core :: OpState") || tokens(arg).ends_with(": & mut deno_core :: OpState")
|| tokens(arg).ends_with("mut OpState")
} }
fn is_rc_refcell_opstate(arg: &syn::FnArg) -> bool { fn is_rc_refcell_opstate(arg: &syn::FnArg) -> bool {
@ -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 v8 :: HandleScope < 'a >")
|| tokens(arg).ends_with(": & mut deno_core :: v8 :: HandleScope") || tokens(arg).ends_with(": & mut deno_core :: v8 :: HandleScope")
|| tokens(arg).ends_with(": & mut deno_core :: v8 :: HandleScope < 'a >") || 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 { fn is_future(ty: impl ToTokens) -> bool {