diff options
author | Matt Mastracci <matthew@mastracci.com> | 2023-03-17 12:22:15 -0600 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-03-17 18:22:15 +0000 |
commit | e55b448730160a6e4df9815a268d4049ac89deab (patch) | |
tree | 35d80fd60f2f1d1d06903caff256484a7d703d76 /core | |
parent | 0bc6bf5d33b8198253954d7f04558270de45c925 (diff) |
feat(core) deno_core::extension! macro to simplify extension registration (#18210)
This implements two macros to simplify extension registration and centralize a lot of the boilerplate as a base for future improvements:
* `deno_core::ops!` registers a block of `#[op]`s, optionally with type
parameters, useful for places where we share lists of ops
* `deno_core::extension!` is used to register an extension, and creates
two methods that can be used at runtime/snapshot generation time:
`init_ops` and `init_ops_and_esm`.
---------
Co-authored-by: Bartek IwaĆczuk <biwanczuk@gmail.com>
Diffstat (limited to 'core')
-rw-r--r-- | core/extensions.rs | 257 | ||||
-rw-r--r-- | core/modules.rs | 7 | ||||
-rw-r--r-- | core/ops_builtin.rs | 103 | ||||
-rw-r--r-- | core/ops_builtin_v8.rs | 37 | ||||
-rw-r--r-- | core/runtime.rs | 166 |
5 files changed, 388 insertions, 182 deletions
diff --git a/core/extensions.rs b/core/extensions.rs index 2c6e1669c..71b9cdb4f 100644 --- a/core/extensions.rs +++ b/core/extensions.rs @@ -65,6 +65,263 @@ impl OpDecl { } } +/// Declares a block of Deno `#[op]`s. The first parameter determines the name of the +/// op declaration block, and is usually `deno_ops`. This block generates a function that +/// returns a [`Vec<OpDecl>`]. +/// +/// This can be either a compact form like: +/// +/// ```no_compile +/// # use deno_core::*; +/// #[op] +/// fn op_xyz() {} +/// +/// deno_core::ops!(deno_ops, [ +/// op_xyz +/// ]); +/// +/// // Use the ops: +/// deno_ops() +/// ``` +/// +/// ... or a parameterized form like so that allows passing a number of type parameters +/// to each `#[op]`: +/// +/// ```no_compile +/// # use deno_core::*; +/// #[op] +/// fn op_xyz<P>() where P: Clone {} +/// +/// deno_core::ops!(deno_ops, +/// parameters = [P: Clone], +/// ops = [ +/// op_xyz<P> +/// ] +/// ); +/// +/// // Use the ops, with `String` as the parameter `P`: +/// deno_ops::<String>() +/// ``` +#[macro_export] +macro_rules! ops { + ($name:ident, parameters = [ $( $param:ident : $type:ident ),+ ], ops = [ $( $(#[$m:meta])* $( $op:ident )::+ $( < $op_param:ident > )? ),+ $(,)? ]) => { + pub(crate) fn $name < $( $param : $type + 'static ),+ > () -> Vec<$crate::OpDecl> { + vec![ + $( + $( #[ $m ] )* + $( $op )::+ :: decl $( :: <$op_param> )? () , + )+ + ] + } + }; + ($name:ident, [ $( $(#[$m:meta])* $( $op:ident )::+ ),+ $(,)? ] ) => { + pub(crate) fn $name() -> Vec<$crate::OpDecl> { + vec![ + $( $( #[ $m ] )* $( $op )::+ :: decl(), )+ + ] + } + } +} + +/// Defines a Deno extension. The first parameter is the name of the extension symbol namespace to create. This is the symbol you +/// will use to refer to the extension. +/// +/// Most extensions will define a combination of ops and ESM files, like so: +/// +/// ```no_compile +/// #[op] +/// fn op_xyz() { +/// } +/// +/// deno_core::extension!( +/// my_extension, +/// ops = [ op_xyz ], +/// esm = [ "my_script.js" ], +/// ); +/// ``` +/// +/// The following options are available for the [`extension`] macro: +/// +/// * deps: a comma-separated list of module dependencies, eg: `deps = [ my_other_extension ]` +/// * parameters: a comma-separated list of parameters and base traits, eg: `parameters = [ P: MyTrait ]` +/// * ops: a comma-separated list of [`OpDecl`]s to provide, eg: `ops = [ op_foo, op_bar ]` +/// * esm: a comma-separated list of ESM module filenames (see [`include_js_files`]), eg: `esm = [ dir "dir", "my_file.js" ]` +/// * esm_setup_script: see [`ExtensionBuilder::esm_setup_script`] +/// * js: a comma-separated list of JS filenames (see [`include_js_files`]), eg: `js = [ dir "dir", "my_file.js" ]` +/// * config: a structure-like definition for configuration parameters which will be required when initializing this extension, eg: `config = { my_param: Option<usize> }` +/// * middleware: an [`OpDecl`] middleware function with the signature `fn (OpDecl) -> OpDecl` +/// * state: a state initialization function, with the signature `fn (&mut OpState, ...) -> ()`, where `...` are parameters matching the fields of the config struct +/// * event_loop_middleware: an event-loop middleware function (see [`ExtensionBuilder::event_loop_middleware`]) +#[macro_export] +macro_rules! extension { + ( + $name:ident + $(, deps = [ $( $dep:ident ),* ] )? + $(, parameters = [ $( $param:ident : $type:ident ),+ ] )? + $(, ops_fn = $ops_symbol:ident $( < $ops_param:ident > )? )? + $(, ops = [ $( $(#[$m:meta])* $( $op:ident )::+ $( < $op_param:ident > )? ),+ $(,)? ] )? + $(, esm_entry_point = $esm_entry_point:literal )? + $(, esm = [ $( dir $dir_esm:literal , )? $( $esm:literal ),* $(,)? ] )? + $(, esm_setup_script = $esm_setup_script:expr )? + $(, js = [ $( dir $dir_js:literal , )? $( $js:literal ),* $(,)? ] )? + $(, config = { $( $config_id:ident : $config_type:ty ),* $(,)? } )? + $(, middleware = $middleware_fn:expr )? + $(, state = $state_fn:expr )? + $(, event_loop_middleware = $event_loop_middleware_fn:ident )? + $(, customizer = $customizer_fn:expr )? + $(,)? + ) => { + /// Extension struct for + #[doc = stringify!($name)] + /// . + #[allow(non_camel_case_types)] + pub struct $name { + } + + impl $name { + #[inline(always)] + fn ext() -> $crate::ExtensionBuilder { + $crate::Extension::builder_with_deps(stringify!($name), &[ $( $( stringify!($dep) ),* )? ]) + } + + /// If ESM or JS was specified, add those files to the extension. + #[inline(always)] + #[allow(unused_variables)] + fn with_js(ext: &mut $crate::ExtensionBuilder) { + $( ext.esm( + $crate::include_js_files!( $( dir $dir_esm , )? $( $esm , )* ) + ); )? + $( + ext.esm(vec![ExtensionFileSource { + specifier: "ext:setup".to_string(), + code: ExtensionFileSourceCode::IncludedInBinary($esm_setup_script), + }]); + )? + $( + ext.esm_entry_point($esm_entry_point); + )? + $( ext.js( + $crate::include_js_files!( $( dir $dir_js , )? $( $js , )* ) + ); )? + } + + // If ops were specified, add those ops to the extension. + #[inline(always)] + #[allow(unused_variables)] + fn with_ops $( < $( $param : $type + Clone + 'static ),+ > )?(ext: &mut $crate::ExtensionBuilder) { + // If individual ops are specified, roll them up into a vector and apply them + $( + let v = vec![ + $( + $( #[ $m ] )* + $( $op )::+ :: decl $( :: <$op_param> )? () + ),+ + ]; + ext.ops(v); + )? + + // Otherwise use the ops_fn, if provided + $crate::extension!(! __ops__ ext $( $ops_symbol $( < $ops_param > )? )? __eot__); + } + + // Includes the state and middleware functions, if defined. + #[inline(always)] + #[allow(unused_variables)] + fn with_state_and_middleware$( < $( $param : $type + Clone + 'static ),+ > )?(ext: &mut $crate::ExtensionBuilder, $( $( $config_id : $config_type ),* )? ) { + #[allow(unused_variables)] + let config = $crate::extension!(! __config__ $( parameters = [ $( $param : $type ),* ] )? $( config = { $( $config_id : $config_type ),* } )? ); + + $( + ext.state(move |state: &mut $crate::OpState| { + config.clone().call_callback(state, $state_fn) + }); + )? + + $( + ext.event_loop_middleware($event_loop_middleware_fn); + )? + + $( + ext.middleware($middleware_fn); + )? + } + + #[inline(always)] + #[allow(unused_variables)] + fn with_customizer(ext: &mut $crate::ExtensionBuilder) { + $( ($customizer_fn)(ext); )? + } + + #[allow(dead_code)] + pub fn init_js_only $( < $( $param : $type + Clone + 'static ),+ > )? () -> $crate::Extension { + let mut ext = Self::ext(); + // If esm or JS was specified, add JS files + Self::with_js(&mut ext); + Self::with_ops $( ::<($( $param ),+)> )?(&mut ext); + Self::with_customizer(&mut ext); + ext.build() + } + + #[allow(dead_code)] + pub fn init_ops_and_esm $( < $( $param : $type + Clone + 'static ),+ > )? ( $( $( $config_id : $config_type ),* )? ) -> $crate::Extension { + let mut ext = Self::ext(); + // If esm or JS was specified, add JS files + Self::with_js(&mut ext); + Self::with_ops $( ::<($( $param ),+)> )?(&mut ext); + Self::with_state_and_middleware $( ::<($( $param ),+)> )?(&mut ext, $( $( $config_id , )* )? ); + Self::with_customizer(&mut ext); + ext.build() + } + + #[allow(dead_code)] + pub fn init_ops $( < $( $param : $type + Clone + 'static ),+ > )? ( $( $( $config_id : $config_type ),* )? ) -> $crate::Extension { + let mut ext = Self::ext(); + Self::with_ops $( ::<($( $param ),+)> )?(&mut ext); + Self::with_state_and_middleware $( ::<($( $param ),+)> )?(&mut ext, $( $( $config_id , )* )? ); + Self::with_customizer(&mut ext); + ext.build() + } + } + }; + + (! __config__ $( parameters = [ $( $param:ident : $type:ident ),+ ] )? $( config = { $( $config_id:ident : $config_type:ty ),* } )? ) => { + { + #[doc(hidden)] + #[derive(Clone)] + struct Config $( < $( $param : $type + Clone + 'static ),+ > )? { + $( $( pub $config_id : $config_type , )* )? + $( __phantom_data: ::std::marker::PhantomData<($( $param ),+)>, )? + } + + impl $( < $( $param : $type + Clone + 'static ),+ > )? Config $( < $( $param ),+ > )? { + /// Call a function of |state, ...| using the fields of this configuration structure. + #[allow(dead_code)] + #[doc(hidden)] + #[inline(always)] + fn call_callback<F: Fn(&mut $crate::OpState, $( $( $config_type ),* )?)>(self, state: &mut $crate::OpState, f: F) { + f(state, $( $( self. $config_id ),* )? ) + } + } + + Config { + $( $( $config_id , )* )? + $( __phantom_data: ::std::marker::PhantomData::<($( $param ),+)>::default() )? + } + } + }; + + (! __ops__ $ext:ident __eot__) => { + }; + + (! __ops__ $ext:ident $ops_symbol:ident __eot__) => { + $ext.ops($ops_symbol()) + }; + + (! __ops__ $ext:ident $ops_symbol:ident < $ops_param:ident > __eot__) => { + $ext.ops($ops_symbol::<$ops_param>()) + }; +} + #[derive(Default)] pub struct Extension { js_files: Option<Vec<ExtensionFileSource>>, diff --git a/core/modules.rs b/core/modules.rs index e03f86c01..ddd55199b 100644 --- a/core/modules.rs +++ b/core/modules.rs @@ -1649,7 +1649,6 @@ impl ModuleMap { #[cfg(test)] mod tests { use super::*; - use crate::Extension; use crate::JsRuntime; use crate::RuntimeOptions; use crate::Snapshot; @@ -1990,12 +1989,10 @@ import "/a.js"; 43 } - let ext = Extension::builder("test_ext") - .ops(vec![op_test::decl()]) - .build(); + deno_core::extension!(test_ext, ops = [op_test]); let mut runtime = JsRuntime::new(RuntimeOptions { - extensions: vec![ext], + extensions: vec![test_ext::init_ops()], module_loader: Some(loader), ..Default::default() }); diff --git a/core/ops_builtin.rs b/core/ops_builtin.rs index 7b66ffaa4..668b44bc3 100644 --- a/core/ops_builtin.rs +++ b/core/ops_builtin.rs @@ -1,13 +1,11 @@ -use crate::ExtensionBuilder; // Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. use crate::error::format_file_name; use crate::error::type_error; -use crate::include_js_files; use crate::io::BufMutView; use crate::io::BufView; +use crate::ops_builtin_v8; use crate::ops_metrics::OpMetrics; use crate::resources::ResourceId; -use crate::Extension; use crate::OpState; use crate::Resource; use crate::ZeroCopyBuf; @@ -19,49 +17,62 @@ use std::io::stdout; use std::io::Write; use std::rc::Rc; -fn ext() -> ExtensionBuilder { - Extension::builder("core") -} - -fn ops(ext: &mut ExtensionBuilder) -> &mut ExtensionBuilder { - let mut ops = vec![ - op_close::decl(), - op_try_close::decl(), - op_print::decl(), - op_resources::decl(), - op_wasm_streaming_feed::decl(), - op_wasm_streaming_set_url::decl(), - op_void_sync::decl(), - op_void_async::decl(), - op_add::decl(), - // // TODO(@AaronO): track IO metrics for builtin streams - op_read::decl(), - op_read_all::decl(), - op_write::decl(), - op_write_all::decl(), - op_shutdown::decl(), - op_metrics::decl(), - op_format_file_name::decl(), - op_is_proxy::decl(), - op_str_byte_length::decl(), - ]; - ops.extend(crate::ops_builtin_v8::init_builtins_v8()); - ext.ops(ops) -} - -pub(crate) fn init_builtin_ops_and_esm() -> Extension { - ops(&mut ext()) - .js(include_js_files!( - "00_primordials.js", - "01_core.js", - "02_error.js", - )) - .build() -} - -pub(crate) fn init_builtin_ops() -> Extension { - ops(&mut ext()).build() -} +crate::extension!( + core, + ops = [ + op_close, + op_try_close, + op_print, + op_resources, + op_wasm_streaming_feed, + op_wasm_streaming_set_url, + op_void_sync, + op_void_async, + op_add, + // TODO(@AaronO): track IO metrics for builtin streams + op_read, + op_read_all, + op_write, + op_write_all, + op_shutdown, + op_metrics, + op_format_file_name, + op_is_proxy, + op_str_byte_length, + ops_builtin_v8::op_ref_op, + ops_builtin_v8::op_unref_op, + ops_builtin_v8::op_set_macrotask_callback, + ops_builtin_v8::op_set_next_tick_callback, + ops_builtin_v8::op_set_promise_reject_callback, + ops_builtin_v8::op_run_microtasks, + ops_builtin_v8::op_has_tick_scheduled, + ops_builtin_v8::op_set_has_tick_scheduled, + ops_builtin_v8::op_eval_context, + ops_builtin_v8::op_queue_microtask, + ops_builtin_v8::op_create_host_object, + ops_builtin_v8::op_encode, + ops_builtin_v8::op_decode, + ops_builtin_v8::op_serialize, + ops_builtin_v8::op_deserialize, + ops_builtin_v8::op_set_promise_hooks, + ops_builtin_v8::op_get_promise_details, + ops_builtin_v8::op_get_proxy_details, + ops_builtin_v8::op_memory_usage, + ops_builtin_v8::op_set_wasm_streaming_callback, + ops_builtin_v8::op_abort_wasm_streaming, + ops_builtin_v8::op_destructure_error, + ops_builtin_v8::op_dispatch_exception, + ops_builtin_v8::op_op_names, + ops_builtin_v8::op_apply_source_map, + ops_builtin_v8::op_set_format_exception_callback, + ops_builtin_v8::op_event_loop_has_more_work, + ops_builtin_v8::op_store_pending_promise_rejection, + ops_builtin_v8::op_remove_pending_promise_rejection, + ops_builtin_v8::op_has_pending_promise_rejection, + ops_builtin_v8::op_arraybuffer_was_detached, + ], + js = ["00_primordials.js", "01_core.js", "02_error.js"], +); /// Return map of resources with id as key /// and string representation as value. diff --git a/core/ops_builtin_v8.rs b/core/ops_builtin_v8.rs index 05250dc73..3d7b4a996 100644 --- a/core/ops_builtin_v8.rs +++ b/core/ops_builtin_v8.rs @@ -11,7 +11,6 @@ use crate::serde_v8::from_v8; use crate::source_map::apply_source_map as apply_source_map_; use crate::JsRealm; use crate::JsRuntime; -use crate::OpDecl; use crate::ZeroCopyBuf; use anyhow::Error; use deno_ops::op; @@ -21,42 +20,6 @@ use std::cell::RefCell; use v8::ValueDeserializerHelper; use v8::ValueSerializerHelper; -pub(crate) fn init_builtins_v8() -> Vec<OpDecl> { - vec![ - op_ref_op::decl(), - op_unref_op::decl(), - op_set_macrotask_callback::decl(), - op_set_next_tick_callback::decl(), - op_set_promise_reject_callback::decl(), - op_run_microtasks::decl(), - op_has_tick_scheduled::decl(), - op_set_has_tick_scheduled::decl(), - op_eval_context::decl(), - op_queue_microtask::decl(), - op_create_host_object::decl(), - op_encode::decl(), - op_decode::decl(), - op_serialize::decl(), - op_deserialize::decl(), - op_set_promise_hooks::decl(), - op_get_promise_details::decl(), - op_get_proxy_details::decl(), - op_memory_usage::decl(), - op_set_wasm_streaming_callback::decl(), - op_abort_wasm_streaming::decl(), - op_destructure_error::decl(), - op_dispatch_exception::decl(), - op_op_names::decl(), - op_apply_source_map::decl(), - op_set_format_exception_callback::decl(), - op_event_loop_has_more_work::decl(), - op_store_pending_promise_rejection::decl(), - op_remove_pending_promise_rejection::decl(), - op_has_pending_promise_rejection::decl(), - op_arraybuffer_was_detached::decl(), - ] -} - fn to_v8_fn( scope: &mut v8::HandleScope, value: serde_v8::Value, diff --git a/core/runtime.rs b/core/runtime.rs index c19765dd9..1ea9c0168 100644 --- a/core/runtime.rs +++ b/core/runtime.rs @@ -323,11 +323,11 @@ impl JsRuntime { if !has_startup_snapshot { options .extensions - .insert(0, crate::ops_builtin::init_builtin_ops_and_esm()); + .insert(0, crate::ops_builtin::core::init_ops_and_esm()); } else { options .extensions - .insert(0, crate::ops_builtin::init_builtin_ops()); + .insert(0, crate::ops_builtin::core::init_ops()); } let ops = Self::collect_ops(&mut options.extensions); @@ -2683,7 +2683,7 @@ pub mod tests { } #[derive(Copy, Clone)] - enum Mode { + pub enum Mode { Async, AsyncDeferred, AsyncZeroCopy(bool), @@ -2728,18 +2728,22 @@ pub mod tests { fn setup(mode: Mode) -> (JsRuntime, Arc<AtomicUsize>) { let dispatch_count = Arc::new(AtomicUsize::new(0)); - let dispatch_count2 = dispatch_count.clone(); - let ext = Extension::builder("test_ext") - .ops(vec![op_test::decl()]) - .state(move |state| { + deno_core::extension!( + test_ext, + ops = [op_test], + config = { + mode: Mode, + dispatch_count: Arc<AtomicUsize>, + }, + state = |state, mode, dispatch_count| { state.put(TestState { mode, - dispatch_count: dispatch_count2.clone(), - }); - }) - .build(); + dispatch_count + }) + } + ); let mut runtime = JsRuntime::new(RuntimeOptions { - extensions: vec![ext], + extensions: vec![test_ext::init_ops(mode, dispatch_count.clone())], get_error_class_fn: Some(&|error| { crate::error::get_custom_error_class(error).unwrap() }), @@ -3149,11 +3153,9 @@ pub mod tests { "DOMExceptionOperationError" } - let ext = Extension::builder("test_ext") - .ops(vec![op_err::decl()]) - .build(); + deno_core::extension!(test_ext, ops = [op_err]); let mut runtime = JsRuntime::new(RuntimeOptions { - extensions: vec![ext], + extensions: vec![test_ext::init_ops()], get_error_class_fn: Some(&get_error_class_name), ..Default::default() }); @@ -3720,11 +3722,9 @@ main(); Err(anyhow!("original async error").context("higher-level async error")) } - let ext = Extension::builder("test_ext") - .ops(vec![op_err_sync::decl(), op_err_async::decl()]) - .build(); + deno_core::extension!(test_ext, ops = [op_err_sync, op_err_async]); let mut runtime = JsRuntime::new(RuntimeOptions { - extensions: vec![ext], + extensions: vec![test_ext::init_ops()], ..Default::default() }); @@ -3889,15 +3889,13 @@ assertEquals(1, notify_return_value); Ok(()) } - let extension = Extension::builder("test_ext") - .ops(vec![op_async_borrow::decl()]) - .state(|state| { - state.put(InnerState(42)); - }) - .build(); - + deno_core::extension!( + test_ext, + ops = [op_async_borrow], + state = |state| state.put(InnerState(42)) + ); let mut runtime = JsRuntime::new(RuntimeOptions { - extensions: vec![extension], + extensions: vec![test_ext::init_ops()], ..Default::default() }); @@ -3923,12 +3921,12 @@ assertEquals(1, notify_return_value); Ok(()) } - let extension = Extension::builder("test_ext") - .ops(vec![op_sync_serialize_object_with_numbers_as_keys::decl()]) - .build(); - + deno_core::extension!( + test_ext, + ops = [op_sync_serialize_object_with_numbers_as_keys] + ); let mut runtime = JsRuntime::new(RuntimeOptions { - extensions: vec![extension], + extensions: vec![test_ext::init_ops()], ..Default::default() }); @@ -3965,12 +3963,12 @@ Deno.core.ops.op_sync_serialize_object_with_numbers_as_keys({ Ok(()) } - let extension = Extension::builder("test_ext") - .ops(vec![op_async_serialize_object_with_numbers_as_keys::decl()]) - .build(); - + deno_core::extension!( + test_ext, + ops = [op_async_serialize_object_with_numbers_as_keys] + ); let mut runtime = JsRuntime::new(RuntimeOptions { - extensions: vec![extension], + extensions: vec![test_ext::init_ops()], ..Default::default() }); @@ -4004,12 +4002,9 @@ Deno.core.opAsync("op_async_serialize_object_with_numbers_as_keys", { Ok(()) } - let extension = Extension::builder("test_ext") - .ops(vec![op_async_sleep::decl()]) - .build(); - + deno_core::extension!(test_ext, ops = [op_async_sleep]); let mut runtime = JsRuntime::new(RuntimeOptions { - extensions: vec![extension], + extensions: vec![test_ext::init_ops()], ..Default::default() }); @@ -4084,12 +4079,9 @@ Deno.core.opAsync("op_async_serialize_object_with_numbers_as_keys", { Ok(()) } - let extension = Extension::builder("test_ext") - .ops(vec![op_macrotask::decl(), op_next_tick::decl()]) - .build(); - + deno_core::extension!(test_ext, ops = [op_macrotask, op_next_tick]); let mut runtime = JsRuntime::new(RuntimeOptions { - extensions: vec![extension], + extensions: vec![test_ext::init_ops()], ..Default::default() }); @@ -4214,12 +4206,9 @@ Deno.core.opAsync("op_async_serialize_object_with_numbers_as_keys", { Ok(()) } - let extension = Extension::builder("test_ext") - .ops(vec![op_promise_reject::decl()]) - .build(); - + deno_core::extension!(test_ext, ops = [op_promise_reject]); let mut runtime = JsRuntime::new(RuntimeOptions { - extensions: vec![extension], + extensions: vec![test_ext::init_ops()], ..Default::default() }); @@ -4321,9 +4310,7 @@ Deno.core.opAsync("op_async_serialize_object_with_numbers_as_keys", { Ok(()) } - let extension = Extension::builder("test_ext") - .ops(vec![op_promise_reject::decl()]) - .build(); + deno_core::extension!(test_ext, ops = [op_promise_reject]); #[derive(Default)] struct ModsLoader; @@ -4367,7 +4354,7 @@ Deno.core.opAsync("op_async_serialize_object_with_numbers_as_keys", { } let mut runtime = JsRuntime::new(RuntimeOptions { - extensions: vec![extension], + extensions: vec![test_ext::init_ops()], module_loader: Some(Rc::new(ModsLoader)), ..Default::default() }); @@ -4390,11 +4377,9 @@ Deno.core.opAsync("op_async_serialize_object_with_numbers_as_keys", { Ok([(1, 2), (3, 4)].into_iter().collect()) // Maps can't have non-string keys in serde_v8 } - let ext = Extension::builder("test_ext") - .ops(vec![op_err::decl()]) - .build(); + deno_core::extension!(test_ext, ops = [op_err]); let mut runtime = JsRuntime::new(RuntimeOptions { - extensions: vec![ext], + extensions: vec![test_ext::init_ops()], ..Default::default() }); assert!(runtime @@ -4417,11 +4402,9 @@ Deno.core.opAsync("op_async_serialize_object_with_numbers_as_keys", { Ok(x1 + x2 + x3 + x4) } - let ext = Extension::builder("test_ext") - .ops(vec![op_add_4::decl()]) - .build(); + deno_core::extension!(test_ext, ops = [op_add_4]); let mut runtime = JsRuntime::new(RuntimeOptions { - extensions: vec![ext], + extensions: vec![test_ext::init_ops()], ..Default::default() }); let r = runtime @@ -4438,11 +4421,13 @@ Deno.core.opAsync("op_async_serialize_object_with_numbers_as_keys", { Ok(42) } - let ext = Extension::builder("test_ext") - .ops(vec![op_foo::decl().disable()]) - .build(); + fn ops() -> Vec<OpDecl> { + vec![op_foo::decl().disable()] + } + + deno_core::extension!(test_ext, ops_fn = ops); let mut runtime = JsRuntime::new(RuntimeOptions { - extensions: vec![ext], + extensions: vec![test_ext::init_ops()], ..Default::default() }); let r = runtime @@ -4468,12 +4453,9 @@ Deno.core.opAsync("op_async_serialize_object_with_numbers_as_keys", { Ok(b) } - let ext = Extension::builder("test_ext") - .ops(vec![op_sum_take::decl(), op_boomerang::decl()]) - .build(); - + deno_core::extension!(test_ext, ops = [op_sum_take, op_boomerang]); let mut runtime = JsRuntime::new(RuntimeOptions { - extensions: vec![ext], + extensions: vec![test_ext::init_ops()], ..Default::default() }); @@ -4536,12 +4518,13 @@ Deno.core.opAsync("op_async_serialize_object_with_numbers_as_keys", { Ok(42) } - let ext = Extension::builder("test_ext") - .ops(vec![op_foo::decl(), op_bar::decl()]) - .middleware(|op| if op.is_unstable { op.disable() } else { op }) - .build(); + deno_core::extension!( + test_ext, + ops = [op_foo, op_bar], + middleware = |op| if op.is_unstable { op.disable() } else { op } + ); let mut runtime = JsRuntime::new(RuntimeOptions { - extensions: vec![ext], + extensions: vec![test_ext::init_ops()], ..Default::default() }); runtime @@ -4587,10 +4570,9 @@ Deno.core.opAsync("op_async_serialize_object_with_numbers_as_keys", { Ok(String::from("Test")) } + deno_core::extension!(test_ext, ops = [op_test]); let mut runtime = JsRuntime::new(RuntimeOptions { - extensions: vec![Extension::builder("test_ext") - .ops(vec![op_test::decl()]) - .build()], + extensions: vec![test_ext::init_ops()], ..Default::default() }); let realm = runtime.create_realm().unwrap(); @@ -4618,11 +4600,10 @@ Deno.core.opAsync("op_async_serialize_object_with_numbers_as_keys", { Ok(String::from("Test")) } + deno_core::extension!(test_ext, ops = [op_test]); let mut runtime = JsRuntime::new(RuntimeOptions { startup_snapshot: Some(Snapshot::Boxed(snapshot)), - extensions: vec![Extension::builder("test_ext") - .ops(vec![op_test::decl()]) - .build()], + extensions: vec![test_ext::init_ops()], ..Default::default() }); let realm = runtime.create_realm().unwrap(); @@ -4650,10 +4631,9 @@ Deno.core.opAsync("op_async_serialize_object_with_numbers_as_keys", { } } + deno_core::extension!(test_ext, ops = [op_test]); let mut runtime = JsRuntime::new(RuntimeOptions { - extensions: vec![Extension::builder("test_ext") - .ops(vec![op_test::decl()]) - .build()], + extensions: vec![test_ext::init_ops()], get_error_class_fn: Some(&|error| { crate::error::get_custom_error_class(error).unwrap() }), @@ -4699,10 +4679,9 @@ Deno.core.opAsync("op_async_serialize_object_with_numbers_as_keys", { } } + deno_core::extension!(test_ext, ops = [op_test]); let mut runtime = JsRuntime::new(RuntimeOptions { - extensions: vec![Extension::builder("test_ext") - .ops(vec![op_test::decl()]) - .build()], + extensions: vec![test_ext::init_ops()], get_error_class_fn: Some(&|error| { crate::error::get_custom_error_class(error).unwrap() }), @@ -4759,10 +4738,9 @@ Deno.core.opAsync("op_async_serialize_object_with_numbers_as_keys", { futures::future::pending().await } + deno_core::extension!(test_ext, ops = [op_pending]); let mut runtime = JsRuntime::new(RuntimeOptions { - extensions: vec![Extension::builder("test_ext") - .ops(vec![op_pending::decl()]) - .build()], + extensions: vec![test_ext::init_ops()], ..Default::default() }); |