diff --git a/core/extensions.rs b/core/extensions.rs index 10de66dd27..94453a6e2e 100644 --- a/core/extensions.rs +++ b/core/extensions.rs @@ -16,6 +16,7 @@ pub struct OpDecl { pub v8_fn_ptr: OpFnRef, pub enabled: bool, pub is_async: bool, // TODO(@AaronO): enum sync/async/fast ? + pub is_unstable: bool, } impl OpDecl { diff --git a/core/runtime.rs b/core/runtime.rs index fd884a7095..bea9908ed8 100644 --- a/core/runtime.rs +++ b/core/runtime.rs @@ -3050,4 +3050,39 @@ assertEquals(1, notify_return_value); let scope = &mut runtime.handle_scope(); assert!(r.open(scope).is_undefined()); } + + #[test] + fn test_op_unstable_disabling() { + #[op] + fn op_foo() -> Result { + Ok(42) + } + + #[op(unstable)] + fn op_bar() -> Result { + Ok(42) + } + + let ext = Extension::builder() + .ops(vec![op_foo::decl(), op_bar::decl()]) + .middleware(|op| if op.is_unstable { op.disable() } else { op }) + .build(); + let mut runtime = JsRuntime::new(RuntimeOptions { + extensions: vec![ext], + ..Default::default() + }); + runtime + .execute_script( + "test.js", + r#" + if (Deno.core.opSync('op_foo') !== 42) { + throw new Error("Exptected op_foo() === 42"); + } + if (Deno.core.opSync('op_bar') !== undefined) { + throw new Error("Expected op_bar to be disabled") + } + "#, + ) + .unwrap(); + } } diff --git a/ops/lib.rs b/ops/lib.rs index 61ad876d31..54f4212bcb 100644 --- a/ops/lib.rs +++ b/ops/lib.rs @@ -34,8 +34,33 @@ fn core_import() -> TokenStream2 { } } +#[derive(Debug)] +struct MacroArgs { + is_unstable: bool, +} + +impl syn::parse::Parse for MacroArgs { + fn parse(input: syn::parse::ParseStream) -> syn::Result { + let vars = + syn::punctuated::Punctuated::::parse_terminated( + input, + )?; + let vars: Vec<_> = vars.iter().map(Ident::to_string).collect(); + let vars: Vec<_> = vars.iter().map(String::as_str).collect(); + match vars[..] { + ["unstable"] => Ok(Self { is_unstable: true }), + [] => Ok(Self { is_unstable: false }), + _ => Err(syn::Error::new( + input.span(), + "Ops expect #[op] or #[op(unstable)]", + )), + } + } +} + #[proc_macro_attribute] -pub fn op(_attr: TokenStream, item: TokenStream) -> TokenStream { +pub fn op(attr: TokenStream, item: TokenStream) -> TokenStream { + let MacroArgs { is_unstable } = syn::parse_macro_input!(attr as MacroArgs); let func = syn::parse::(item).expect("expected a function"); let name = &func.sig.ident; let generics = &func.sig.generics; @@ -85,6 +110,7 @@ pub fn op(_attr: TokenStream, item: TokenStream) -> TokenStream { v8_fn_ptr: Self::v8_fn_ptr::<#type_params>(), enabled: true, is_async: #is_async, + is_unstable: #is_unstable, } }