From 805ce6fdf70f09e9b3f73b48d42e475a4189a904 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Thu, 1 Sep 2022 15:53:06 +0530 Subject: [PATCH] feat(ops): support `v8::FastApiCallbackOptions` (#15721) --- ops/lib.rs | 44 ++++++++++++++++++----- ops/tests/01_fast_callback_options.rs | 11 ++++++ ops/tests/compile_fail/unsupported.rs | 7 ++++ ops/tests/compile_fail/unsupported.stderr | 20 +++++++++-- ops/tests/mod.rs | 1 + 5 files changed, 72 insertions(+), 11 deletions(-) create mode 100644 ops/tests/01_fast_callback_options.rs diff --git a/ops/lib.rs b/ops/lib.rs index 7d291d1da5..437fa3b7e2 100644 --- a/ops/lib.rs +++ b/ops/lib.rs @@ -304,24 +304,29 @@ fn codegen_fast_impl( args, ret, use_recv, + use_fast_cb_opts, v8_values, }) = fast_info { + let offset = if use_recv { 1 } else { 0 }; let inputs = &f .sig .inputs .iter() - .skip(if use_recv { 1 } else { 0 }) + .skip(offset) .enumerate() .map(|(idx, arg)| { + let ident = match arg { + FnArg::Receiver(_) => unreachable!(), + FnArg::Typed(t) => match &*t.pat { + syn::Pat::Ident(i) => format_ident!("{}", i.ident), + _ => unreachable!(), + }, + }; + if use_fast_cb_opts && idx == f.sig.inputs.len() - 1 { + return quote! { #ident: *mut #core::v8::fast_api::FastApiCallbackOptions }; + } if v8_values.contains(&idx) { - let ident = match arg { - FnArg::Receiver(_) => unreachable!(), - FnArg::Typed(t) => match &*t.pat { - syn::Pat::Ident(i) => format_ident!("{}", i.ident), - _ => unreachable!(), - }, - }; return quote! { #ident: #core::v8::Local < #core::v8::Value > }; } quote!(#arg) @@ -340,6 +345,9 @@ fn codegen_fast_impl( _ => unreachable!(), }, }; + if use_fast_cb_opts && idx == f.sig.inputs.len() - 1 { + return quote! { Some(unsafe { &mut * #ident }) }; + } if v8_values.contains(&idx) { return quote! { #core::serde_v8::Value { @@ -479,6 +487,7 @@ struct FastApiSyn { args: TokenStream2, ret: TokenStream2, use_recv: bool, + use_fast_cb_opts: bool, v8_values: Vec, } @@ -493,9 +502,16 @@ fn can_be_fast_api(core: &TokenStream2, f: &syn::ItemFn) -> Option { }; let mut use_recv = false; + let mut use_fast_cb_opts = false; let mut v8_values = Vec::new(); let mut args = vec![quote! { #core::v8::fast_api::Type::V8Value }]; for (pos, input) in inputs.iter().enumerate() { + if pos == inputs.len() - 1 && is_optional_fast_callback_option(input) { + args.push(quote! { #core::v8::fast_api::Type::CallbackOptions }); + use_fast_cb_opts = true; + continue; + } + if pos == 0 && is_mut_ref_opstate(input) { use_recv = true; continue; @@ -535,6 +551,7 @@ fn can_be_fast_api(core: &TokenStream2, f: &syn::ItemFn) -> Option { ret, use_recv, v8_values, + use_fast_cb_opts, }) } @@ -638,7 +655,12 @@ fn codegen_arg( ) -> TokenStream2 { let ident = quote::format_ident!("{name}"); let (pat, ty) = match arg { - syn::FnArg::Typed(pat) => (&pat.pat, &pat.ty), + syn::FnArg::Typed(pat) => { + if is_optional_fast_callback_option(&pat.ty) { + return quote! { let #ident = None; }; + } + (&pat.pat, &pat.ty) + } _ => unreachable!(), }; // Fast path if arg should be skipped @@ -753,6 +775,10 @@ fn is_option_string(ty: impl ToTokens) -> bool { tokens(ty) == "Option < String >" } +fn is_optional_fast_callback_option(ty: impl ToTokens) -> bool { + tokens(&ty).contains("Option < & mut FastApiCallbackOptions") +} + /// Detects if the type can be set using `rv.set_uint32` fast path fn is_u32_rv(ty: impl ToTokens) -> bool { ["u32", "u8", "u16"].iter().any(|&s| tokens(&ty) == s) || is_resource_id(&ty) diff --git a/ops/tests/01_fast_callback_options.rs b/ops/tests/01_fast_callback_options.rs new file mode 100644 index 0000000000..815d9262c8 --- /dev/null +++ b/ops/tests/01_fast_callback_options.rs @@ -0,0 +1,11 @@ +use deno_core::v8::fast_api::FastApiCallbackOptions; +use deno_ops::op; + +#[op(fast)] +fn op_fallback(options: Option<&mut FastApiCallbackOptions>) { + if let Some(options) = options { + options.fallback = true; + } +} + +fn main() {} diff --git a/ops/tests/compile_fail/unsupported.rs b/ops/tests/compile_fail/unsupported.rs index 1c4d6407ad..52d55de5b9 100644 --- a/ops/tests/compile_fail/unsupported.rs +++ b/ops/tests/compile_fail/unsupported.rs @@ -17,6 +17,13 @@ fn op_u16_arg(a: u16, b: u16) { // } +use deno_core::v8::fast_api::FastApiCallbackOptions; + +#[op(fast)] +fn op_callback_options(options: &mut FastApiCallbackOptions) { + // fast callback options must be an Option. +} + #[op(fast)] async fn op_async_fn(a: i32, b: i32) -> i32 { a + b diff --git a/ops/tests/compile_fail/unsupported.stderr b/ops/tests/compile_fail/unsupported.stderr index 68c9f7f162..88d1c1fe4b 100644 --- a/ops/tests/compile_fail/unsupported.stderr +++ b/ops/tests/compile_fail/unsupported.stderr @@ -23,9 +23,25 @@ error: custom attribute panicked = help: message: op cannot be a fast api. enforced by #[op(fast)] error: custom attribute panicked - --> tests/compile_fail/unsupported.rs:20:1 + --> tests/compile_fail/unsupported.rs:22:1 | -20 | #[op(fast)] +22 | #[op(fast)] + | ^^^^^^^^^^^ + | + = help: message: op cannot be a fast api. enforced by #[op(fast)] + +error: custom attribute panicked + --> tests/compile_fail/unsupported.rs:27:1 + | +27 | #[op(fast)] | ^^^^^^^^^^^ | = help: message: async op cannot be a fast api. enforced by #[op(fast)] + +warning: unused import: `deno_core::v8::fast_api::FastApiCallbackOptions` + --> tests/compile_fail/unsupported.rs:20:5 + | +20 | use deno_core::v8::fast_api::FastApiCallbackOptions; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(unused_imports)]` on by default diff --git a/ops/tests/mod.rs b/ops/tests/mod.rs index 522647f51e..699bcf9f4c 100644 --- a/ops/tests/mod.rs +++ b/ops/tests/mod.rs @@ -2,4 +2,5 @@ fn op_macro() { let t = trybuild::TestCases::new(); t.compile_fail("tests/compile_fail/*.rs"); + t.pass("tests/01_fast_callback_options.rs"); }