refactor(extensions): reintroduce builder (#10412)

This commit is contained in:
Aaron O'Mullan 2021-04-29 00:16:45 +02:00 committed by GitHub
parent e63c533154
commit e89295b176
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 141 additions and 112 deletions

View file

@ -15,38 +15,13 @@ pub struct Extension {
initialized: bool, initialized: bool,
} }
impl Extension {
pub fn new(
js_files: Option<Vec<SourcePair>>,
ops: Option<Vec<OpPair>>,
opstate_fn: Option<Box<OpStateFn>>,
middleware_fn: Option<Box<OpMiddlewareFn>>,
) -> Self {
Self {
js_files,
ops,
opstate_fn,
middleware_fn,
initialized: false,
}
}
pub fn pure_js(js_files: Vec<SourcePair>) -> Self {
Self::new(Some(js_files), None, None, None)
}
pub fn with_ops(
js_files: Vec<SourcePair>,
ops: Vec<OpPair>,
opstate_fn: Option<Box<OpStateFn>>,
) -> Self {
Self::new(Some(js_files), Some(ops), opstate_fn, None)
}
}
// Note: this used to be a trait, but we "downgraded" it to a single concrete type // Note: this used to be a trait, but we "downgraded" it to a single concrete type
// for the initial iteration, it will likely become a trait in the future // for the initial iteration, it will likely become a trait in the future
impl Extension { impl Extension {
pub fn builder() -> ExtensionBuilder {
Default::default()
}
/// returns JS source code to be loaded into the isolate (either at snapshotting, /// returns JS source code to be loaded into the isolate (either at snapshotting,
/// or at startup). as a vector of a tuple of the file name, and the source code. /// or at startup). as a vector of a tuple of the file name, and the source code.
pub(crate) fn init_js(&self) -> Vec<SourcePair> { pub(crate) fn init_js(&self) -> Vec<SourcePair> {
@ -81,6 +56,54 @@ impl Extension {
} }
} }
// Provides a convenient builder pattern to declare Extensions
#[derive(Default)]
pub struct ExtensionBuilder {
js: Vec<SourcePair>,
ops: Vec<OpPair>,
state: Option<Box<OpStateFn>>,
middleware: Option<Box<OpMiddlewareFn>>,
}
impl ExtensionBuilder {
pub fn js(&mut self, js_files: Vec<SourcePair>) -> &mut Self {
self.js.extend(js_files);
self
}
pub fn ops(&mut self, ops: Vec<OpPair>) -> &mut Self {
self.ops.extend(ops);
self
}
pub fn state<F>(&mut self, opstate_fn: F) -> &mut Self
where
F: Fn(&mut OpState) -> Result<(), AnyError> + 'static,
{
self.state = Some(Box::new(opstate_fn));
self
}
pub fn middleware<F>(&mut self, middleware_fn: F) -> &mut Self
where
F: Fn(&'static str, Box<OpFn>) -> Box<OpFn> + 'static,
{
self.middleware = Some(Box::new(middleware_fn));
self
}
pub fn build(&mut self) -> Extension {
let js_files = Some(std::mem::take(&mut self.js));
let ops = Some(std::mem::take(&mut self.ops));
Extension {
js_files,
ops,
opstate_fn: self.state.take(),
middleware_fn: self.middleware.take(),
initialized: false,
}
}
}
/// Helps embed JS files in an extension. Returns Vec<(&'static str, &'static str)> /// Helps embed JS files in an extension. Returns Vec<(&'static str, &'static str)>
/// representing the filename and source code. /// representing the filename and source code.
/// ///

View file

@ -5,11 +5,13 @@ use deno_core::Extension;
use std::path::PathBuf; use std::path::PathBuf;
pub fn init() -> Extension { pub fn init() -> Extension {
Extension::pure_js(include_js_files!( Extension::builder()
prefix "deno:op_crates/console", .js(include_js_files!(
"01_colors.js", prefix "deno:op_crates/console",
"02_console.js", "01_colors.js",
)) "02_console.js",
))
.build()
} }
pub fn get_declaration() -> PathBuf { pub fn get_declaration() -> PathBuf {

View file

@ -16,22 +16,22 @@ use std::path::PathBuf;
pub use rand; // Re-export rand pub use rand; // Re-export rand
pub fn init(maybe_seed: Option<u64>) -> Extension { pub fn init(maybe_seed: Option<u64>) -> Extension {
Extension::with_ops( Extension::builder()
include_js_files!( .js(include_js_files!(
prefix "deno:op_crates/crypto", prefix "deno:op_crates/crypto",
"01_crypto.js", "01_crypto.js",
), ))
vec![( .ops(vec![(
"op_crypto_get_random_values", "op_crypto_get_random_values",
op_sync(op_crypto_get_random_values), op_sync(op_crypto_get_random_values),
)], )])
Some(Box::new(move |state| { .state(move |state| {
if let Some(seed) = maybe_seed { if let Some(seed) = maybe_seed {
state.put(StdRng::seed_from_u64(seed)); state.put(StdRng::seed_from_u64(seed));
} }
Ok(()) Ok(())
})), })
) .build()
} }
pub fn op_crypto_get_random_values( pub fn op_crypto_get_random_values(

View file

@ -56,8 +56,8 @@ pub fn init<P: FetchPermissions + 'static>(
user_agent: String, user_agent: String,
ca_data: Option<Vec<u8>>, ca_data: Option<Vec<u8>>,
) -> Extension { ) -> Extension {
Extension::with_ops( Extension::builder()
include_js_files!( .js(include_js_files!(
prefix "deno:op_crates/fetch", prefix "deno:op_crates/fetch",
"01_fetch_util.js", "01_fetch_util.js",
"11_streams.js", "11_streams.js",
@ -68,15 +68,15 @@ pub fn init<P: FetchPermissions + 'static>(
"23_request.js", "23_request.js",
"23_response.js", "23_response.js",
"26_fetch.js", "26_fetch.js",
), ))
vec![ .ops(vec![
("op_fetch", op_sync(op_fetch::<P>)), ("op_fetch", op_sync(op_fetch::<P>)),
("op_fetch_send", op_async(op_fetch_send)), ("op_fetch_send", op_async(op_fetch_send)),
("op_fetch_request_write", op_async(op_fetch_request_write)), ("op_fetch_request_write", op_async(op_fetch_request_write)),
("op_fetch_response_read", op_async(op_fetch_response_read)), ("op_fetch_response_read", op_async(op_fetch_response_read)),
("op_create_http_client", op_sync(op_create_http_client::<P>)), ("op_create_http_client", op_sync(op_create_http_client::<P>)),
], ])
Some(Box::new(move |state| { .state(move |state| {
state.put::<reqwest::Client>({ state.put::<reqwest::Client>({
create_http_client(user_agent.clone(), ca_data.clone()).unwrap() create_http_client(user_agent.clone(), ca_data.clone()).unwrap()
}); });
@ -85,8 +85,8 @@ pub fn init<P: FetchPermissions + 'static>(
user_agent: user_agent.clone(), user_agent: user_agent.clone(),
}); });
Ok(()) Ok(())
})), })
) .build()
} }
pub struct HttpClientDefaults { pub struct HttpClientDefaults {

View file

@ -88,14 +88,14 @@ pub fn init(
blob_url_store: BlobUrlStore, blob_url_store: BlobUrlStore,
maybe_location: Option<Url>, maybe_location: Option<Url>,
) -> Extension { ) -> Extension {
Extension::with_ops( Extension::builder()
include_js_files!( .js(include_js_files!(
prefix "deno:op_crates/file", prefix "deno:op_crates/file",
"01_file.js", "01_file.js",
"02_filereader.js", "02_filereader.js",
"03_blob_url.js", "03_blob_url.js",
), ))
vec![ .ops(vec![
( (
"op_file_create_object_url", "op_file_create_object_url",
op_sync(op_file_create_object_url), op_sync(op_file_create_object_url),
@ -104,15 +104,15 @@ pub fn init(
"op_file_revoke_object_url", "op_file_revoke_object_url",
op_sync(op_file_revoke_object_url), op_sync(op_file_revoke_object_url),
), ),
], ])
Some(Box::new(move |state| { .state(move |state| {
state.put(blob_url_store.clone()); state.put(blob_url_store.clone());
if let Some(location) = maybe_location.clone() { if let Some(location) = maybe_location.clone() {
state.put(Location(location)); state.put(Location(location));
} }
Ok(()) Ok(())
})), })
) .build()
} }
pub fn get_declaration() -> PathBuf { pub fn get_declaration() -> PathBuf {

View file

@ -13,6 +13,7 @@ use deno_core::futures;
use deno_core::futures::channel::oneshot; use deno_core::futures::channel::oneshot;
use deno_core::futures::FutureExt; use deno_core::futures::FutureExt;
use deno_core::futures::TryFutureExt; use deno_core::futures::TryFutureExt;
use deno_core::include_js_files;
use deno_core::op_async; use deno_core::op_async;
use deno_core::op_sync; use deno_core::op_sync;
use deno_core::Extension; use deno_core::Extension;
@ -41,24 +42,24 @@ impl TimersPermission for NoTimersPermission {
} }
pub fn init<P: TimersPermission + 'static>() -> Extension { pub fn init<P: TimersPermission + 'static>() -> Extension {
Extension::with_ops( Extension::builder()
vec![( .js(include_js_files!(
"deno:op_crates/timers/01_timers.js", prefix "deno:op_crates/timers",
include_str!("01_timers.js"), "01_timers.js",
)], ))
vec![ .ops(vec![
("op_global_timer_stop", op_sync(op_global_timer_stop)), ("op_global_timer_stop", op_sync(op_global_timer_stop)),
("op_global_timer_start", op_sync(op_global_timer_start)), ("op_global_timer_start", op_sync(op_global_timer_start)),
("op_global_timer", op_async(op_global_timer)), ("op_global_timer", op_async(op_global_timer)),
("op_now", op_sync(op_now::<P>)), ("op_now", op_sync(op_now::<P>)),
("op_sleep_sync", op_sync(op_sleep_sync::<P>)), ("op_sleep_sync", op_sync(op_sleep_sync::<P>)),
], ])
Some(Box::new(|state| { .state(|state| {
state.put(GlobalTimer::default()); state.put(GlobalTimer::default());
state.put(StartTime::now()); state.put(StartTime::now());
Ok(()) Ok(())
})), })
) .build()
} }
pub type StartTime = Instant; pub type StartTime = Instant;

View file

@ -17,12 +17,12 @@ use std::panic::catch_unwind;
use std::path::PathBuf; use std::path::PathBuf;
pub fn init() -> Extension { pub fn init() -> Extension {
Extension::with_ops( Extension::builder()
include_js_files!( .js(include_js_files!(
prefix "deno:op_crates/url", prefix "deno:op_crates/url",
"00_url.js", "00_url.js",
), ))
vec![ .ops(vec![
("op_url_parse", op_sync(op_url_parse)), ("op_url_parse", op_sync(op_url_parse)),
( (
"op_url_parse_search_params", "op_url_parse_search_params",
@ -32,9 +32,8 @@ pub fn init() -> Extension {
"op_url_stringify_search_params", "op_url_stringify_search_params",
op_sync(op_url_stringify_search_params), op_sync(op_url_stringify_search_params),
), ),
], ])
None, .build()
)
} }
#[derive(Deserialize)] #[derive(Deserialize)]

View file

@ -6,17 +6,19 @@ use std::path::PathBuf;
/// Load and execute the javascript code. /// Load and execute the javascript code.
pub fn init() -> Extension { pub fn init() -> Extension {
Extension::pure_js(include_js_files!( Extension::builder()
prefix "deno:op_crates/web", .js(include_js_files!(
"00_infra.js", prefix "deno:op_crates/web",
"01_dom_exception.js", "00_infra.js",
"01_mimesniff.js", "01_dom_exception.js",
"02_event.js", "01_mimesniff.js",
"03_abort_signal.js", "02_event.js",
"04_global_interfaces.js", "03_abort_signal.js",
"08_text_encoding.js", "04_global_interfaces.js",
"12_location.js", "08_text_encoding.js",
)) "12_location.js",
))
.build()
} }
pub fn get_declaration() -> PathBuf { pub fn get_declaration() -> PathBuf {

View file

@ -95,22 +95,22 @@ impl Resource for WebGpuQuerySet {
} }
pub fn init(unstable: bool) -> Extension { pub fn init(unstable: bool) -> Extension {
Extension::with_ops( Extension::builder()
include_js_files!( .js(include_js_files!(
prefix "deno:op_crates/webgpu", prefix "deno:op_crates/webgpu",
"01_webgpu.js", "01_webgpu.js",
"02_idl_types.js", "02_idl_types.js",
), ))
declare_webgpu_ops(), .ops(declare_webgpu_ops())
Some(Box::new(move |state| { .state(move |state| {
// TODO: check & possibly streamline this // TODO: check & possibly streamline this
// Unstable might be able to be OpMiddleware // Unstable might be able to be OpMiddleware
// let unstable_checker = state.borrow::<super::UnstableChecker>(); // let unstable_checker = state.borrow::<super::UnstableChecker>();
// let unstable = unstable_checker.unstable; // let unstable = unstable_checker.unstable;
state.put(Unstable(unstable)); state.put(Unstable(unstable));
Ok(()) Ok(())
})), })
) .build()
} }
pub fn get_declaration() -> PathBuf { pub fn get_declaration() -> PathBuf {

View file

@ -1,11 +1,14 @@
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
use deno_core::include_js_files;
use deno_core::Extension; use deno_core::Extension;
/// Load and execute the javascript code. /// Load and execute the javascript code.
pub fn init() -> Extension { pub fn init() -> Extension {
Extension::pure_js(vec![( Extension::builder()
"deno:op_crates/webidl/00_webidl.js", .js(include_js_files!(
include_str!("00_webidl.js"), prefix "deno:op_crates/webidl",
)]) "00_webidl.js",
))
.build()
} }

View file

@ -340,12 +340,12 @@ pub fn init<P: WebSocketPermissions + 'static>(
user_agent: String, user_agent: String,
ca_data: Option<Vec<u8>>, ca_data: Option<Vec<u8>>,
) -> Extension { ) -> Extension {
Extension::with_ops( Extension::builder()
include_js_files!( .js(include_js_files!(
prefix "deno:op_crates/websocket", prefix "deno:op_crates/websocket",
"01_websocket.js", "01_websocket.js",
), ))
vec![ .ops(vec![
( (
"op_ws_check_permission", "op_ws_check_permission",
op_sync(op_ws_check_permission::<P>), op_sync(op_ws_check_permission::<P>),
@ -354,15 +354,15 @@ pub fn init<P: WebSocketPermissions + 'static>(
("op_ws_send", op_async(op_ws_send)), ("op_ws_send", op_async(op_ws_send)),
("op_ws_close", op_async(op_ws_close)), ("op_ws_close", op_async(op_ws_close)),
("op_ws_next_event", op_async(op_ws_next_event)), ("op_ws_next_event", op_async(op_ws_next_event)),
], ])
Some(Box::new(move |state| { .state(move |state| {
state.put::<WsUserAgent>(WsUserAgent(user_agent.clone())); state.put::<WsUserAgent>(WsUserAgent(user_agent.clone()));
if let Some(ca_data) = ca_data.clone() { if let Some(ca_data) = ca_data.clone() {
state.put::<WsCaData>(WsCaData(ca_data)); state.put::<WsCaData>(WsCaData(ca_data));
} }
Ok(()) Ok(())
})), })
) .build()
} }
pub fn get_declaration() -> PathBuf { pub fn get_declaration() -> PathBuf {

View file

@ -10,15 +10,14 @@ use deno_core::OpState;
use deno_core::ZeroCopyBuf; use deno_core::ZeroCopyBuf;
pub fn init() -> Extension { pub fn init() -> Extension {
Extension::new( Extension::builder()
None, .ops(vec![("op_metrics", op_sync(op_metrics))])
Some(vec![("op_metrics", op_sync(op_metrics))]), .state(|state| {
Some(Box::new(|state| {
state.put(RuntimeMetrics::default()); state.put(RuntimeMetrics::default());
Ok(()) Ok(())
})), })
Some(Box::new(metrics_op)), .middleware(metrics_op)
) .build()
} }
#[derive(serde::Serialize)] #[derive(serde::Serialize)]