1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-12-23 15:49:44 -05:00

feat(core): codegen ops (#13861)

Co-authored-by: Aaron O'Mullan <aaron.omullan@gmail.com>
This commit is contained in:
Divy Srivastava 2022-03-14 23:14:15 +05:30 committed by GitHub
parent 4e3ed37037
commit b4e42953e1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
78 changed files with 1754 additions and 1664 deletions

21
Cargo.lock generated
View file

@ -856,6 +856,7 @@ version = "0.122.0"
dependencies = [
"anyhow",
"deno_ast",
"deno_ops",
"futures",
"indexmap",
"libc",
@ -1019,6 +1020,16 @@ dependencies = [
"trust-dns-resolver",
]
[[package]]
name = "deno_ops"
version = "0.1.1"
dependencies = [
"proc-macro-crate",
"proc-macro2 1.0.36",
"quote 1.0.14",
"syn 1.0.85",
]
[[package]]
name = "deno_runtime"
version = "0.48.0"
@ -2925,6 +2936,16 @@ dependencies = [
"output_vt100",
]
[[package]]
name = "proc-macro-crate"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e17d47ce914bf4de440332250b0edd23ce48c005f59fab39d3335866b114f11a"
dependencies = [
"thiserror",
"toml",
]
[[package]]
name = "proc-macro-error"
version = "1.0.4"

View file

@ -6,6 +6,7 @@ members = [
"bench_util",
"cli",
"core",
"ops",
"runtime",
"serde_v8",
"test_ffi",

View file

@ -3,11 +3,9 @@ use deno_bench_util::bencher::{benchmark_group, Bencher};
use deno_bench_util::{bench_js_async, bench_js_sync};
use deno_core::error::AnyError;
use deno_core::op_async;
use deno_core::op_sync;
use deno_core::serialize_op_result;
use deno_core::op;
use deno_core::Extension;
use deno_core::Op;
use deno_core::OpState;
use std::cell::RefCell;
@ -16,17 +14,25 @@ use std::rc::Rc;
fn setup() -> Vec<Extension> {
vec![Extension::builder()
.ops(vec![
("pi_json", op_sync(|_, _: (), _: ()| Ok(314159))),
("pi_async", op_async(op_pi_async)),
(
"nop",
Box::new(|state, _| Op::Sync(serialize_op_result(Ok(9), state))),
),
op_pi_json::decl(),
op_pi_async::decl(),
op_nop::decl(),
])
.build()]
}
#[op]
fn op_nop(_: &mut OpState, _: (), _: ()) -> Result<(), AnyError> {
Ok(())
}
#[op]
fn op_pi_json(_: &mut OpState, _: (), _: ()) -> Result<i64, AnyError> {
Ok(314159)
}
// this is a function since async closures aren't stable
#[op]
async fn op_pi_async(
_: Rc<RefCell<OpState>>,
_: (),
@ -36,15 +42,15 @@ async fn op_pi_async(
}
fn bench_op_pi_json(b: &mut Bencher) {
bench_js_sync(b, r#"Deno.core.opSync("pi_json", null);"#, setup);
bench_js_sync(b, r#"Deno.core.opSync("op_pi_json", null);"#, setup);
}
fn bench_op_nop(b: &mut Bencher) {
bench_js_sync(b, r#"Deno.core.opSync("nop", null, null, null);"#, setup);
bench_js_sync(b, r#"Deno.core.opSync("op_nop", null, null, null);"#, setup);
}
fn bench_op_async(b: &mut Bencher) {
bench_js_async(b, r#"Deno.core.opAsync("pi_async", null);"#, setup);
bench_js_async(b, r#"Deno.core.opAsync("op_pi_async", null);"#, setup);
}
fn bench_is_proxy(b: &mut Bencher) {
@ -58,4 +64,5 @@ benchmark_group!(
bench_op_async,
bench_is_proxy
);
bench_or_profile!(benches);

View file

@ -1,11 +1,14 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
use deno_core::error::custom_error;
use deno_core::op_sync;
use deno_core::error::AnyError;
use deno_core::op;
use deno_core::serde::Deserialize;
use deno_core::serde_json::json;
use deno_core::serde_json::Value;
use deno_core::Extension;
use deno_core::JsRuntime;
use deno_core::OpState;
use deno_core::RuntimeOptions;
use regex::Regex;
use std::collections::HashMap;
@ -185,79 +188,112 @@ fn create_compiler_snapshot(
build_libs.push(op_lib.to_owned());
}
let re_asset = Regex::new(r"asset:/{3}lib\.(\S+)\.d\.ts").expect("bad regex");
let build_specifier = "asset:///bootstrap.ts";
#[op]
fn op_build_info(
state: &mut OpState,
_args: Value,
_: (),
) -> Result<Value, AnyError> {
let build_specifier = "asset:///bootstrap.ts";
let build_libs = state.borrow::<Vec<&str>>();
Ok(json!({
"buildSpecifier": build_specifier,
"libs": build_libs,
}))
}
let mut js_runtime = JsRuntime::new(RuntimeOptions {
will_snapshot: true,
..Default::default()
});
js_runtime.register_op(
"op_build_info",
op_sync(move |_state, _args: Value, _: ()| {
Ok(json!({
"buildSpecifier": build_specifier,
"libs": build_libs,
}))
}),
);
js_runtime.register_op(
"op_cwd",
op_sync(move |_state, _args: Value, _: ()| Ok(json!("cache:///"))),
);
// As of TypeScript 4.5, it tries to detect the existence of substitute lib
// files, which we currently don't use, so we just return false.
js_runtime.register_op(
"op_exists",
op_sync(move |_state, _args: LoadArgs, _: ()| Ok(json!(false))),
);
#[op]
fn op_cwd(
_state: &mut OpState,
_args: Value,
_: (),
) -> Result<Value, AnyError> {
Ok(json!("cache:///"))
}
#[op]
fn op_exists(
_state: &mut OpState,
_args: Value,
_: (),
) -> Result<Value, AnyError> {
Ok(json!(false))
}
#[op]
// using the same op that is used in `tsc.rs` for loading modules and reading
// files, but a slightly different implementation at build time.
js_runtime.register_op(
"op_load",
op_sync(move |_state, args: LoadArgs, _: ()| {
// we need a basic file to send to tsc to warm it up.
if args.specifier == build_specifier {
fn op_load(
state: &mut OpState,
args: LoadArgs,
_: (),
) -> Result<Value, AnyError> {
let op_crate_libs = state.borrow::<HashMap<&str, &str>>();
let path_dts = state.borrow::<PathBuf>();
let re_asset =
Regex::new(r"asset:/{3}lib\.(\S+)\.d\.ts").expect("bad regex");
let build_specifier = "asset:///bootstrap.ts";
// we need a basic file to send to tsc to warm it up.
if args.specifier == build_specifier {
Ok(json!({
"data": r#"console.log("hello deno!");"#,
"hash": "1",
// this corresponds to `ts.ScriptKind.TypeScript`
"scriptKind": 3
}))
// specifiers come across as `asset:///lib.{lib_name}.d.ts` and we need to
// parse out just the name so we can lookup the asset.
} else if let Some(caps) = re_asset.captures(&args.specifier) {
if let Some(lib) = caps.get(1).map(|m| m.as_str()) {
// if it comes from an op crate, we were supplied with the path to the
// file.
let path = if let Some(op_crate_lib) = op_crate_libs.get(lib) {
PathBuf::from(op_crate_lib).canonicalize().unwrap()
// otherwise we are will generate the path ourself
} else {
path_dts.join(format!("lib.{}.d.ts", lib))
};
let data = std::fs::read_to_string(path)?;
Ok(json!({
"data": r#"console.log("hello deno!");"#,
"data": data,
"hash": "1",
// this corresponds to `ts.ScriptKind.TypeScript`
"scriptKind": 3
}))
// specifiers come across as `asset:///lib.{lib_name}.d.ts` and we need to
// parse out just the name so we can lookup the asset.
} else if let Some(caps) = re_asset.captures(&args.specifier) {
if let Some(lib) = caps.get(1).map(|m| m.as_str()) {
// if it comes from an op crate, we were supplied with the path to the
// file.
let path = if let Some(op_crate_lib) = op_crate_libs.get(lib) {
PathBuf::from(op_crate_lib).canonicalize().unwrap()
// otherwise we are will generate the path ourself
} else {
path_dts.join(format!("lib.{}.d.ts", lib))
};
let data = std::fs::read_to_string(path)?;
Ok(json!({
"data": data,
"hash": "1",
// this corresponds to `ts.ScriptKind.TypeScript`
"scriptKind": 3
}))
} else {
Err(custom_error(
"InvalidSpecifier",
format!("An invalid specifier was requested: {}", args.specifier),
))
}
} else {
Err(custom_error(
"InvalidSpecifier",
format!("An invalid specifier was requested: {}", args.specifier),
))
}
}),
);
js_runtime.sync_ops_cache();
} else {
Err(custom_error(
"InvalidSpecifier",
format!("An invalid specifier was requested: {}", args.specifier),
))
}
}
let js_runtime = JsRuntime::new(RuntimeOptions {
will_snapshot: true,
extensions: vec![Extension::builder()
.ops(vec![
op_build_info::decl(),
op_cwd::decl(),
op_exists::decl(),
op_load::decl(),
])
.state(move |state| {
state.put(op_crate_libs.clone());
state.put(build_libs.clone());
state.put(path_dts.clone());
Ok(())
})
.build()],
..Default::default()
});
create_snapshot(js_runtime, snapshot_path, files);
}

View file

@ -27,7 +27,7 @@ use deno_core::anyhow::anyhow;
use deno_core::error::custom_error;
use deno_core::error::AnyError;
use deno_core::located_script_name;
use deno_core::op_sync;
use deno_core::op;
use deno_core::parking_lot::Mutex;
use deno_core::resolve_url;
use deno_core::serde::de;
@ -40,7 +40,7 @@ use deno_core::url::Url;
use deno_core::Extension;
use deno_core::JsRuntime;
use deno_core::ModuleSpecifier;
use deno_core::OpFn;
use deno_core::OpState;
use deno_core::RuntimeOptions;
use deno_runtime::tokio_util::create_basic_runtime;
use log::error;
@ -2502,19 +2502,6 @@ fn normalize_specifier<S: AsRef<str>>(
.map_err(|err| err.into())
}
// buffer-less json_sync ops
fn op_lsp<F, V, R>(op_fn: F) -> Box<OpFn>
where
F: Fn(&mut State, V) -> Result<R, AnyError> + 'static,
V: de::DeserializeOwned,
R: Serialize + 'static,
{
op_sync(move |s, args, _: ()| {
let state = s.borrow_mut::<State>();
op_fn(state, args)
})
}
#[derive(Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
struct SourceSnapshotArgs {
@ -2524,10 +2511,13 @@ struct SourceSnapshotArgs {
/// The language service is dropping a reference to a source file snapshot, and
/// we can drop our version of that document.
#[op]
fn op_dispose(
state: &mut State,
state: &mut OpState,
args: SourceSnapshotArgs,
_: (),
) -> Result<bool, AnyError> {
let state = state.borrow_mut::<State>();
let mark = state.performance.mark("op_dispose", Some(&args));
let specifier = state.normalize_specifier(&args.specifier)?;
state.snapshots.remove(&(specifier, args.version.into()));
@ -2541,7 +2531,13 @@ struct SpecifierArgs {
specifier: String,
}
fn op_exists(state: &mut State, args: SpecifierArgs) -> Result<bool, AnyError> {
#[op]
fn op_exists(
state: &mut OpState,
args: SpecifierArgs,
_: (),
) -> Result<bool, AnyError> {
let state = state.borrow_mut::<State>();
// we don't measure the performance of op_exists anymore because as of TS 4.5
// it is noisy with all the checking for custom libs, that we can't see the
// forrest for the trees as well as it compounds any lsp performance
@ -2569,10 +2565,13 @@ struct GetChangeRangeArgs {
/// The language service wants to compare an old snapshot with a new snapshot to
/// determine what source has changed.
#[op]
fn op_get_change_range(
state: &mut State,
state: &mut OpState,
args: GetChangeRangeArgs,
_: (),
) -> Result<Value, AnyError> {
let state = state.borrow_mut::<State>();
let mark = state.performance.mark("op_get_change_range", Some(&args));
let specifier = state.normalize_specifier(&args.specifier)?;
cache_snapshot(state, &specifier, args.version.clone())?;
@ -2613,10 +2612,13 @@ fn op_get_change_range(
r
}
#[op]
fn op_get_length(
state: &mut State,
state: &mut OpState,
args: SourceSnapshotArgs,
_: (),
) -> Result<usize, AnyError> {
let state = state.borrow_mut::<State>();
let mark = state.performance.mark("op_get_length", Some(&args));
let specifier = state.normalize_specifier(args.specifier)?;
let r = if let Some(Some(asset)) =
@ -2644,10 +2646,13 @@ struct GetTextArgs {
end: usize,
}
#[op]
fn op_get_text(
state: &mut State,
state: &mut OpState,
args: GetTextArgs,
_: (),
) -> Result<String, AnyError> {
let state = state.borrow_mut::<State>();
let mark = state.performance.mark("op_get_text", Some(&args));
let specifier = state.normalize_specifier(args.specifier)?;
let maybe_asset = state.state_snapshot.assets.get_cached(&specifier);
@ -2664,14 +2669,23 @@ fn op_get_text(
Ok(text::slice(content, args.start..args.end).to_string())
}
fn op_is_cancelled(state: &mut State, _: ()) -> Result<bool, AnyError> {
#[op]
fn op_is_cancelled(
state: &mut OpState,
_: (),
_: (),
) -> Result<bool, AnyError> {
let state = state.borrow_mut::<State>();
Ok(state.token.is_cancelled())
}
#[op]
fn op_load(
state: &mut State,
state: &mut OpState,
args: SpecifierArgs,
_: (),
) -> Result<Option<String>, AnyError> {
let state = state.borrow_mut::<State>();
let mark = state.performance.mark("op_load", Some(&args));
let specifier = state.normalize_specifier(args.specifier)?;
let document = state.state_snapshot.documents.get(&specifier);
@ -2679,10 +2693,13 @@ fn op_load(
Ok(document.map(|d| d.content().to_string()))
}
#[op]
fn op_resolve(
state: &mut State,
state: &mut OpState,
args: ResolveArgs,
_: (),
) -> Result<Vec<Option<(String, String)>>, AnyError> {
let state = state.borrow_mut::<State>();
let mark = state.performance.mark("op_resolve", Some(&args));
let referrer = state.normalize_specifier(&args.base)?;
@ -2713,15 +2730,24 @@ fn op_resolve(
result
}
fn op_respond(state: &mut State, args: Response) -> Result<bool, AnyError> {
#[op]
fn op_respond(
state: &mut OpState,
args: Response,
_: (),
) -> Result<bool, AnyError> {
let state = state.borrow_mut::<State>();
state.response = Some(args);
Ok(true)
}
#[op]
fn op_script_names(
state: &mut State,
state: &mut OpState,
_args: Value,
_: (),
) -> Result<Vec<ModuleSpecifier>, AnyError> {
let state = state.borrow_mut::<State>();
Ok(
state
.state_snapshot
@ -2739,10 +2765,13 @@ struct ScriptVersionArgs {
specifier: String,
}
#[op]
fn op_script_version(
state: &mut State,
state: &mut OpState,
args: ScriptVersionArgs,
_: (),
) -> Result<Option<String>, AnyError> {
let state = state.borrow_mut::<State>();
// this op is very "noisy" and measuring its performance is not useful, so we
// don't measure it uniquely anymore.
let specifier = state.normalize_specifier(args.specifier)?;
@ -2776,17 +2805,17 @@ fn js_runtime(performance: Arc<Performance>) -> JsRuntime {
fn init_extension(performance: Arc<Performance>) -> Extension {
Extension::builder()
.ops(vec![
("op_dispose", op_lsp(op_dispose)),
("op_exists", op_lsp(op_exists)),
("op_get_change_range", op_lsp(op_get_change_range)),
("op_get_length", op_lsp(op_get_length)),
("op_get_text", op_lsp(op_get_text)),
("op_is_cancelled", op_lsp(op_is_cancelled)),
("op_load", op_lsp(op_load)),
("op_resolve", op_lsp(op_resolve)),
("op_respond", op_lsp(op_respond)),
("op_script_names", op_lsp(op_script_names)),
("op_script_version", op_lsp(op_script_version)),
op_dispose::decl(),
op_exists::decl(),
op_get_change_range::decl(),
op_get_length::decl(),
op_get_text::decl(),
op_is_cancelled::decl(),
op_load::decl(),
op_resolve::decl(),
op_respond::decl(),
op_script_names::decl(),
op_script_version::decl(),
])
.state(move |state| {
state.put(State::new(
@ -3832,7 +3861,7 @@ mod tests {
#[test]
fn test_op_exists() {
let (_, state_snapshot, _) = setup(
let (mut rt, state_snapshot, _) = setup(
false,
json!({
"target": "esnext",
@ -3843,12 +3872,16 @@ mod tests {
&[],
);
let performance = Arc::new(Performance::default());
let mut state = State::new(state_snapshot, performance);
let actual = op_exists(
&mut state,
let state = State::new(state_snapshot, performance);
let op_state = rt.op_state();
let mut op_state = op_state.borrow_mut();
op_state.put(state);
let actual = op_exists::call(
&mut op_state,
SpecifierArgs {
specifier: "/error/unknown:something/index.d.ts".to_string(),
},
(),
);
assert!(actual.is_ok());
let actual = actual.unwrap();

View file

@ -1,7 +1,7 @@
use crate::tools::bench::BenchEvent;
use deno_core::error::generic_error;
use deno_core::error::AnyError;
use deno_core::op_sync;
use deno_core::op;
use deno_core::Extension;
use deno_core::ModuleSpecifier;
use deno_core::OpState;
@ -15,17 +15,11 @@ use uuid::Uuid;
pub fn init(sender: UnboundedSender<BenchEvent>) -> Extension {
Extension::builder()
.ops(vec![
(
"op_pledge_test_permissions",
op_sync(op_pledge_test_permissions),
),
(
"op_restore_test_permissions",
op_sync(op_restore_test_permissions),
),
("op_get_bench_origin", op_sync(op_get_bench_origin)),
("op_dispatch_bench_event", op_sync(op_dispatch_bench_event)),
("op_bench_now", op_sync(op_bench_now)),
op_pledge_test_permissions::decl(),
op_restore_test_permissions::decl(),
op_get_bench_origin::decl(),
op_dispatch_bench_event::decl(),
op_bench_now::decl(),
])
.state(move |state| {
state.put(sender.clone());
@ -37,6 +31,7 @@ pub fn init(sender: UnboundedSender<BenchEvent>) -> Extension {
#[derive(Clone)]
struct PermissionsHolder(Uuid, Permissions);
#[op]
pub fn op_pledge_test_permissions(
state: &mut OpState,
args: ChildPermissionsArg,
@ -55,6 +50,7 @@ pub fn op_pledge_test_permissions(
Ok(token)
}
#[op]
pub fn op_restore_test_permissions(
state: &mut OpState,
token: Uuid,
@ -73,6 +69,7 @@ pub fn op_restore_test_permissions(
}
}
#[op]
fn op_get_bench_origin(
state: &mut OpState,
_: (),
@ -81,6 +78,7 @@ fn op_get_bench_origin(
Ok(state.borrow::<ModuleSpecifier>().to_string())
}
#[op]
fn op_dispatch_bench_event(
state: &mut OpState,
event: BenchEvent,
@ -92,6 +90,7 @@ fn op_dispatch_bench_event(
Ok(())
}
#[op]
fn op_bench_now(state: &mut OpState, _: (), _: ()) -> Result<u64, AnyError> {
let ns = state.borrow::<time::Instant>().elapsed().as_nanos();
let ns_u64 = u64::try_from(ns)?;

View file

@ -6,7 +6,7 @@ use crate::proc_state::ProcState;
use crate::source_maps::get_orig_position;
use crate::source_maps::CachedMaps;
use deno_core::error::AnyError;
use deno_core::op_sync;
use deno_core::op;
use deno_core::serde_json;
use deno_core::serde_json::json;
use deno_core::serde_json::Value;
@ -19,9 +19,9 @@ use std::collections::HashMap;
pub fn init() -> Extension {
Extension::builder()
.ops(vec![
("op_apply_source_map", op_sync(op_apply_source_map)),
("op_format_diagnostic", op_sync(op_format_diagnostic)),
("op_format_file_name", op_sync(op_format_file_name)),
op_apply_source_map::decl(),
op_format_diagnostic::decl(),
op_format_file_name::decl(),
])
.build()
}
@ -42,6 +42,7 @@ struct AppliedSourceMap {
column_number: u32,
}
#[op]
fn op_apply_source_map(
state: &mut OpState,
args: ApplySourceMap,
@ -66,6 +67,7 @@ fn op_apply_source_map(
})
}
#[op]
fn op_format_diagnostic(
_state: &mut OpState,
args: Value,
@ -75,6 +77,7 @@ fn op_format_diagnostic(
Ok(json!(diagnostic.to_string()))
}
#[op]
fn op_format_file_name(
_state: &mut OpState,
file_name: String,

View file

@ -16,7 +16,8 @@ use deno_core::anyhow::Context;
use deno_core::error::custom_error;
use deno_core::error::generic_error;
use deno_core::error::AnyError;
use deno_core::op_async;
use deno_core::op;
use deno_core::parking_lot::RwLock;
use deno_core::resolve_url_or_path;
use deno_core::serde_json;
@ -35,9 +36,7 @@ use std::rc::Rc;
use std::sync::Arc;
pub fn init() -> Extension {
Extension::builder()
.ops(vec![("op_emit", op_async(op_emit))])
.build()
Extension::builder().ops(vec![op_emit::decl()]).build()
}
#[derive(Debug, Deserialize)]
@ -141,6 +140,7 @@ fn to_maybe_jsx_import_source_module(
}
}
#[op]
async fn op_emit(
state: Rc<RefCell<OpState>>,
args: EmitArgs,

View file

@ -1,7 +1,7 @@
use crate::tools::test::TestEvent;
use deno_core::error::generic_error;
use deno_core::error::AnyError;
use deno_core::op_sync;
use deno_core::op;
use deno_core::Extension;
use deno_core::ModuleSpecifier;
use deno_core::OpState;
@ -14,16 +14,10 @@ use uuid::Uuid;
pub fn init(sender: UnboundedSender<TestEvent>) -> Extension {
Extension::builder()
.ops(vec![
(
"op_pledge_test_permissions",
op_sync(op_pledge_test_permissions),
),
(
"op_restore_test_permissions",
op_sync(op_restore_test_permissions),
),
("op_get_test_origin", op_sync(op_get_test_origin)),
("op_dispatch_test_event", op_sync(op_dispatch_test_event)),
op_pledge_test_permissions::decl(),
op_restore_test_permissions::decl(),
op_get_test_origin::decl(),
op_dispatch_test_event::decl(),
])
.state(move |state| {
state.put(sender.clone());
@ -35,6 +29,7 @@ pub fn init(sender: UnboundedSender<TestEvent>) -> Extension {
#[derive(Clone)]
struct PermissionsHolder(Uuid, Permissions);
#[op]
pub fn op_pledge_test_permissions(
state: &mut OpState,
args: ChildPermissionsArg,
@ -53,6 +48,7 @@ pub fn op_pledge_test_permissions(
Ok(token)
}
#[op]
pub fn op_restore_test_permissions(
state: &mut OpState,
token: Uuid,
@ -71,6 +67,7 @@ pub fn op_restore_test_permissions(
}
}
#[op]
fn op_get_test_origin(
state: &mut OpState,
_: (),
@ -79,6 +76,7 @@ fn op_get_test_origin(
Ok(state.borrow::<ModuleSpecifier>().to_string())
}
#[op]
fn op_dispatch_test_event(
state: &mut OpState,
event: TestEvent,

View file

@ -11,18 +11,18 @@ use deno_core::anyhow::anyhow;
use deno_core::anyhow::Context;
use deno_core::error::AnyError;
use deno_core::located_script_name;
use deno_core::op_sync;
use deno_core::op;
use deno_core::parking_lot::RwLock;
use deno_core::resolve_url_or_path;
use deno_core::serde::de;
use deno_core::serde::Deserialize;
use deno_core::serde::Serialize;
use deno_core::serde_json;
use deno_core::serde_json::json;
use deno_core::serde_json::Value;
use deno_core::Extension;
use deno_core::JsRuntime;
use deno_core::ModuleSpecifier;
use deno_core::OpFn;
use deno_core::OpState;
use deno_core::RuntimeOptions;
use deno_core::Snapshot;
use deno_graph::Resolved;
@ -298,18 +298,6 @@ fn normalize_specifier(specifier: &str) -> Result<ModuleSpecifier, AnyError> {
.map_err(|err| err.into())
}
fn op<F, V, R>(op_fn: F) -> Box<OpFn>
where
F: Fn(&mut State, V) -> Result<R, AnyError> + 'static,
V: de::DeserializeOwned,
R: Serialize + 'static,
{
op_sync(move |s, args, _: ()| {
let state = s.borrow_mut::<State>();
op_fn(state, args)
})
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
struct CreateHashArgs {
@ -318,7 +306,13 @@ struct CreateHashArgs {
data: String,
}
fn op_create_hash(state: &mut State, args: Value) -> Result<Value, AnyError> {
#[op]
fn op_create_hash(
s: &mut OpState,
args: Value,
_: (),
) -> Result<Value, AnyError> {
let state = s.borrow_mut::<State>();
let v: CreateHashArgs = serde_json::from_value(args)
.context("Invalid request from JavaScript for \"op_create_hash\".")?;
let mut data = vec![v.data.as_bytes().to_owned()];
@ -327,7 +321,9 @@ fn op_create_hash(state: &mut State, args: Value) -> Result<Value, AnyError> {
Ok(json!({ "hash": hash }))
}
fn op_cwd(state: &mut State, _args: Value) -> Result<String, AnyError> {
#[op]
fn op_cwd(s: &mut OpState, _args: Value, _: ()) -> Result<String, AnyError> {
let state = s.borrow_mut::<State>();
if let Some(config_specifier) = &state.maybe_config_specifier {
let cwd = config_specifier.join("./")?;
Ok(cwd.to_string())
@ -350,7 +346,13 @@ struct EmitArgs {
maybe_specifiers: Option<Vec<String>>,
}
fn op_emit(state: &mut State, args: EmitArgs) -> Result<Value, AnyError> {
#[op]
fn op_emit(
state: &mut OpState,
args: EmitArgs,
_: (),
) -> Result<Value, AnyError> {
let state = state.borrow_mut::<State>();
match args.file_name.as_ref() {
"deno:///.tsbuildinfo" => state.maybe_tsbuildinfo = Some(args.data),
_ => {
@ -403,7 +405,13 @@ struct ExistsArgs {
specifier: String,
}
fn op_exists(state: &mut State, args: ExistsArgs) -> Result<bool, AnyError> {
#[op]
fn op_exists(
state: &mut OpState,
args: ExistsArgs,
_: (),
) -> Result<bool, AnyError> {
let state = state.borrow_mut::<State>();
let graph_data = state.graph_data.read();
if let Ok(specifier) = normalize_specifier(&args.specifier) {
if specifier.scheme() == "asset" || specifier.scheme() == "data" {
@ -443,7 +451,9 @@ fn as_ts_script_kind(media_type: &MediaType) -> i32 {
}
}
fn op_load(state: &mut State, args: Value) -> Result<Value, AnyError> {
#[op]
fn op_load(state: &mut OpState, args: Value, _: ()) -> Result<Value, AnyError> {
let state = state.borrow_mut::<State>();
let v: LoadArgs = serde_json::from_value(args)
.context("Invalid request from JavaScript for \"op_load\".")?;
let specifier = normalize_specifier(&v.specifier)
@ -507,7 +517,13 @@ pub struct ResolveArgs {
pub specifiers: Vec<String>,
}
fn op_resolve(state: &mut State, args: ResolveArgs) -> Result<Value, AnyError> {
#[op]
fn op_resolve(
state: &mut OpState,
args: ResolveArgs,
_: (),
) -> Result<Value, AnyError> {
let state = state.borrow_mut::<State>();
let mut resolved: Vec<(String, String)> = Vec::new();
let referrer = if let Some(remapped_specifier) =
state.remapped_specifiers.get(&args.base)
@ -612,7 +628,13 @@ struct RespondArgs {
pub stats: emit::Stats,
}
fn op_respond(state: &mut State, args: Value) -> Result<Value, AnyError> {
#[op]
fn op_respond(
state: &mut OpState,
args: Value,
_: (),
) -> Result<Value, AnyError> {
let state = state.borrow_mut::<State>();
let v: RespondArgs = serde_json::from_value(args)
.context("Error converting the result for \"op_respond\".")?;
state.maybe_response = Some(v);
@ -623,10 +645,6 @@ fn op_respond(state: &mut State, args: Value) -> Result<Value, AnyError> {
/// contains information, like any emitted files, diagnostics, statistics and
/// optionally an updated TypeScript build info.
pub(crate) fn exec(request: Request) -> Result<Response, AnyError> {
let mut runtime = JsRuntime::new(RuntimeOptions {
startup_snapshot: Some(compiler_snapshot()),
..Default::default()
});
// tsc cannot handle root specifiers that don't have one of the "acceptable"
// extensions. Therefore, we have to check the root modules against their
// extensions and remap any that are unacceptable to tsc and add them to the
@ -654,28 +672,32 @@ pub(crate) fn exec(request: Request) -> Result<Response, AnyError> {
}
})
.collect();
{
let op_state = runtime.op_state();
let mut op_state = op_state.borrow_mut();
op_state.put(State::new(
request.graph_data,
request.hash_data.clone(),
request.maybe_config_specifier.clone(),
request.maybe_tsbuildinfo.clone(),
root_map,
remapped_specifiers,
));
}
runtime.register_op("op_cwd", op(op_cwd));
runtime.register_op("op_create_hash", op(op_create_hash));
runtime.register_op("op_emit", op(op_emit));
runtime.register_op("op_exists", op(op_exists));
runtime.register_op("op_load", op(op_load));
runtime.register_op("op_resolve", op(op_resolve));
runtime.register_op("op_respond", op(op_respond));
runtime.sync_ops_cache();
let mut runtime = JsRuntime::new(RuntimeOptions {
startup_snapshot: Some(compiler_snapshot()),
extensions: vec![Extension::builder()
.ops(vec![
op_cwd::decl(),
op_create_hash::decl(),
op_emit::decl(),
op_exists::decl(),
op_load::decl(),
op_resolve::decl(),
op_respond::decl(),
])
.state(move |state| {
state.put(State::new(
request.graph_data.clone(),
request.hash_data.clone(),
request.maybe_config_specifier.clone(),
request.maybe_tsbuildinfo.clone(),
root_map.clone(),
remapped_specifiers.clone(),
));
Ok(())
})
.build()],
..Default::default()
});
let startup_source = "globalThis.startup({ legacyFlag: false })";
let request_value = json!({
@ -720,6 +742,7 @@ mod tests {
use crate::diagnostics::DiagnosticCategory;
use crate::emit::Stats;
use deno_core::futures::future;
use deno_core::OpState;
use deno_graph::ModuleKind;
use std::fs;
@ -757,7 +780,7 @@ mod tests {
maybe_specifier: Option<ModuleSpecifier>,
maybe_hash_data: Option<Vec<Vec<u8>>>,
maybe_tsbuildinfo: Option<String>,
) -> State {
) -> OpState {
let specifier = maybe_specifier
.unwrap_or_else(|| resolve_url_or_path("file:///main.ts").unwrap());
let hash_data = maybe_hash_data.unwrap_or_else(|| vec![b"".to_vec()]);
@ -774,14 +797,17 @@ mod tests {
None,
)
.await;
State::new(
let state = State::new(
Arc::new(RwLock::new((&graph).into())),
hash_data,
None,
maybe_tsbuildinfo,
HashMap::new(),
HashMap::new(),
)
);
let mut op_state = OpState::new(1);
op_state.put(state);
op_state
}
async fn test_exec(
@ -852,9 +878,12 @@ mod tests {
#[tokio::test]
async fn test_create_hash() {
let mut state = setup(None, Some(vec![b"something".to_vec()]), None).await;
let actual =
op_create_hash(&mut state, json!({ "data": "some sort of content" }))
.expect("could not invoke op");
let actual = op_create_hash::call(
&mut state,
json!({ "data": "some sort of content" }),
(),
)
.expect("could not invoke op");
assert_eq!(
actual,
json!({"hash": "ae92df8f104748768838916857a1623b6a3c593110131b0a00f81ad9dac16511"})
@ -898,16 +927,18 @@ mod tests {
#[tokio::test]
async fn test_emit() {
let mut state = setup(None, None, None).await;
let actual = op_emit(
let actual = op_emit::call(
&mut state,
EmitArgs {
data: "some file content".to_string(),
file_name: "cache:///some/file.js".to_string(),
maybe_specifiers: Some(vec!["file:///some/file.ts".to_string()]),
},
(),
)
.expect("should have invoked op");
assert_eq!(actual, json!(true));
let state = state.borrow::<State>();
assert_eq!(state.emitted_files.len(), 1);
assert!(state.maybe_tsbuildinfo.is_none());
assert_eq!(
@ -926,7 +957,7 @@ mod tests {
#[tokio::test]
async fn test_emit_strange_specifier() {
let mut state = setup(None, None, None).await;
let actual = op_emit(
let actual = op_emit::call(
&mut state,
EmitArgs {
data: "some file content".to_string(),
@ -935,9 +966,11 @@ mod tests {
vec!["file:///some/file.ts?q=.json".to_string()],
),
},
(),
)
.expect("should have invoked op");
assert_eq!(actual, json!(true));
let state = state.borrow::<State>();
assert_eq!(state.emitted_files.len(), 1);
assert!(state.maybe_tsbuildinfo.is_none());
assert_eq!(
@ -956,16 +989,18 @@ mod tests {
#[tokio::test]
async fn test_emit_tsbuildinfo() {
let mut state = setup(None, None, None).await;
let actual = op_emit(
let actual = op_emit::call(
&mut state,
EmitArgs {
data: "some file content".to_string(),
file_name: "deno:///.tsbuildinfo".to_string(),
maybe_specifiers: None,
},
(),
)
.expect("should have invoked op");
assert_eq!(actual, json!(true));
let state = state.borrow::<State>();
assert_eq!(state.emitted_files.len(), 0);
assert_eq!(
state.maybe_tsbuildinfo,
@ -981,9 +1016,10 @@ mod tests {
Some("some content".to_string()),
)
.await;
let actual = op_load(
let actual = op_load::call(
&mut state,
json!({ "specifier": "https://deno.land/x/mod.ts"}),
(),
)
.expect("should have invoked op");
assert_eq!(
@ -1012,9 +1048,12 @@ mod tests {
Some("some content".to_string()),
)
.await;
let value =
op_load(&mut state, json!({ "specifier": "asset:///lib.dom.d.ts" }))
.expect("should have invoked op");
let value = op_load::call(
&mut state,
json!({ "specifier": "asset:///lib.dom.d.ts" }),
(),
)
.expect("should have invoked op");
let actual: LoadResponse =
serde_json::from_value(value).expect("failed to deserialize");
let expected = get_asset("lib.dom.d.ts").unwrap();
@ -1031,9 +1070,12 @@ mod tests {
Some("some content".to_string()),
)
.await;
let actual =
op_load(&mut state, json!({ "specifier": "deno:///.tsbuildinfo"}))
.expect("should have invoked op");
let actual = op_load::call(
&mut state,
json!({ "specifier": "deno:///.tsbuildinfo"}),
(),
)
.expect("should have invoked op");
assert_eq!(
actual,
json!({
@ -1047,9 +1089,10 @@ mod tests {
#[tokio::test]
async fn test_load_missing_specifier() {
let mut state = setup(None, None, None).await;
let actual = op_load(
let actual = op_load::call(
&mut state,
json!({ "specifier": "https://deno.land/x/mod.ts"}),
(),
)
.expect("should have invoked op");
assert_eq!(
@ -1070,12 +1113,13 @@ mod tests {
None,
)
.await;
let actual = op_resolve(
let actual = op_resolve::call(
&mut state,
ResolveArgs {
base: "https://deno.land/x/a.ts".to_string(),
specifiers: vec!["./b.ts".to_string()],
},
(),
)
.expect("should have invoked op");
assert_eq!(actual, json!([["https://deno.land/x/b.ts", ".ts"]]));
@ -1089,12 +1133,13 @@ mod tests {
None,
)
.await;
let actual = op_resolve(
let actual = op_resolve::call(
&mut state,
ResolveArgs {
base: "https://deno.land/x/a.ts".to_string(),
specifiers: vec!["./bad.ts".to_string()],
},
(),
)
.expect("should have not errored");
assert_eq!(
@ -1106,7 +1151,7 @@ mod tests {
#[tokio::test]
async fn test_respond() {
let mut state = setup(None, None, None).await;
let actual = op_respond(
let actual = op_respond::call(
&mut state,
json!({
"diagnostics": [
@ -1118,9 +1163,11 @@ mod tests {
],
"stats": [["a", 12]]
}),
(),
)
.expect("should have invoked op");
assert_eq!(actual, json!(true));
let state = state.borrow::<State>();
assert_eq!(
state.maybe_response,
Some(RespondArgs {

View file

@ -921,6 +921,7 @@ delete Object.prototype.__proto__;
// A build time only op that provides some setup information that is used to
// ensure the snapshot is setup properly.
/** @type {{ buildSpecifier: string; libs: string[] }} */
const { buildSpecifier, libs } = core.opSync("op_build_info", {});
for (const lib of libs) {
const specifier = `lib.${lib}.d.ts`;

View file

@ -16,7 +16,6 @@
ErrorCaptureStackTrace,
Promise,
ObjectEntries,
ObjectFreeze,
ObjectFromEntries,
MapPrototypeGet,
MapPrototypeDelete,
@ -27,11 +26,12 @@
ObjectAssign,
SymbolFor,
} = window.__bootstrap.primordials;
const ops = window.Deno.core.ops;
const opIds = Object.keys(ops).reduce((a, v, i) => ({ ...a, [v]: i }), {});
// Available on start due to bindings.
const { opcallSync, opcallAsync, refOp_, unrefOp_ } = window.Deno.core;
const { refOp_, unrefOp_ } = window.Deno.core;
let opsCache = {};
const errorMap = {};
// Builtin v8 / JS errors
registerErrorClass("Error", Error);
@ -110,15 +110,6 @@
return promiseRing[idx] != NO_PROMISE;
}
function ops() {
return opsCache;
}
function syncOpsCache() {
// op id 0 is a special value to retrieve the map of registered ops.
opsCache = ObjectFreeze(ObjectFromEntries(opcallSync(0)));
}
function opresolve() {
for (let i = 0; i < arguments.length; i += 2) {
const promiseId = arguments[i];
@ -160,7 +151,7 @@
function opAsync(opName, arg1 = null, arg2 = null) {
const promiseId = nextPromiseId++;
const maybeError = opcallAsync(opsCache[opName], promiseId, arg1, arg2);
const maybeError = ops[opName](opIds[opName], promiseId, arg1, arg2);
// Handle sync error (e.g: error parsing args)
if (maybeError) return unwrapOpResult(maybeError);
let p = PromisePrototypeThen(setPromise(promiseId), unwrapOpResult);
@ -179,8 +170,8 @@
return p;
}
function opSync(opName, arg1 = null, arg2 = null) {
return unwrapOpResult(opcallSync(opsCache[opName], arg1, arg2));
function opSync(opName, arg1, arg2) {
return unwrapOpResult(ops[opName](opIds[opName], arg1, arg2));
}
function refOp(promiseId) {
@ -228,7 +219,7 @@
function metrics() {
const [aggregate, perOps] = opSync("op_metrics");
aggregate.ops = ObjectFromEntries(ArrayPrototypeMap(
ObjectEntries(opsCache),
ObjectEntries(opIds),
([opName, opId]) => [opName, perOps[opId]],
));
return aggregate;
@ -257,7 +248,6 @@
const core = ObjectAssign(globalThis.Deno.core, {
opAsync,
opSync,
ops,
close,
tryClose,
read,
@ -269,7 +259,6 @@
registerErrorBuilder,
registerErrorClass,
opresolve,
syncOpsCache,
BadResource,
BadResourcePrototype,
Interrupted,

View file

@ -14,6 +14,7 @@ path = "lib.rs"
[dependencies]
anyhow = "1.0.55"
deno_ops = { path = "../ops", version = "0.1.0" }
futures = "0.3.21"
indexmap = "1.7.0"
libc = "0.2.106"

View file

@ -1,6 +1,7 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
use crate::error::is_instance_of_error;
use crate::extensions::OpPair;
use crate::modules::get_module_type_from_assertions;
use crate::modules::parse_import_assertions;
use crate::modules::validate_import_assertions;
@ -8,21 +9,18 @@ use crate::modules::ImportAssertionsKind;
use crate::modules::ModuleMap;
use crate::resolve_url_or_path;
use crate::JsRuntime;
use crate::Op;
use crate::OpId;
use crate::OpPayload;
use crate::OpResult;
use crate::OpTable;
use crate::OpState;
use crate::PromiseId;
use crate::ZeroCopyBuf;
use anyhow::Error;
use log::debug;
use once_cell::sync::Lazy;
use serde::Deserialize;
use serde::Serialize;
use serde_v8::to_v8;
use std::cell::RefCell;
use std::option::Option;
use std::os::raw::c_void;
use std::rc::Rc;
use url::Url;
use v8::HandleScope;
use v8::Local;
@ -31,88 +29,88 @@ use v8::SharedArrayBuffer;
use v8::ValueDeserializerHelper;
use v8::ValueSerializerHelper;
const UNDEFINED_OP_ID_MSG: &str =
"invalid op id: received `undefined` instead of an integer.
This error is often caused by a typo in an op name, or not calling
JsRuntime::sync_ops_cache() after JsRuntime initialization.";
pub static EXTERNAL_REFERENCES: Lazy<v8::ExternalReferences> =
Lazy::new(|| {
v8::ExternalReferences::new(&[
v8::ExternalReference {
function: opcall_async.map_fn_to(),
},
v8::ExternalReference {
function: opcall_sync.map_fn_to(),
},
v8::ExternalReference {
function: ref_op.map_fn_to(),
},
v8::ExternalReference {
function: unref_op.map_fn_to(),
},
v8::ExternalReference {
function: set_macrotask_callback.map_fn_to(),
},
v8::ExternalReference {
function: set_nexttick_callback.map_fn_to(),
},
v8::ExternalReference {
function: set_promise_reject_callback.map_fn_to(),
},
v8::ExternalReference {
function: set_uncaught_exception_callback.map_fn_to(),
},
v8::ExternalReference {
function: run_microtasks.map_fn_to(),
},
v8::ExternalReference {
function: has_tick_scheduled.map_fn_to(),
},
v8::ExternalReference {
function: set_has_tick_scheduled.map_fn_to(),
},
v8::ExternalReference {
function: eval_context.map_fn_to(),
},
v8::ExternalReference {
function: queue_microtask.map_fn_to(),
},
v8::ExternalReference {
function: create_host_object.map_fn_to(),
},
v8::ExternalReference {
function: encode.map_fn_to(),
},
v8::ExternalReference {
function: decode.map_fn_to(),
},
v8::ExternalReference {
function: serialize.map_fn_to(),
},
v8::ExternalReference {
function: deserialize.map_fn_to(),
},
v8::ExternalReference {
function: get_promise_details.map_fn_to(),
},
v8::ExternalReference {
function: get_proxy_details.map_fn_to(),
},
v8::ExternalReference {
function: is_proxy.map_fn_to(),
},
v8::ExternalReference {
function: memory_usage.map_fn_to(),
},
v8::ExternalReference {
function: call_console.map_fn_to(),
},
v8::ExternalReference {
function: set_wasm_streaming_callback.map_fn_to(),
},
])
pub fn external_references(
ops: &[OpPair],
op_state: Rc<RefCell<OpState>>,
) -> v8::ExternalReferences {
let mut refs = vec![
v8::ExternalReference {
function: ref_op.map_fn_to(),
},
v8::ExternalReference {
function: unref_op.map_fn_to(),
},
v8::ExternalReference {
function: set_macrotask_callback.map_fn_to(),
},
v8::ExternalReference {
function: set_nexttick_callback.map_fn_to(),
},
v8::ExternalReference {
function: set_promise_reject_callback.map_fn_to(),
},
v8::ExternalReference {
function: set_uncaught_exception_callback.map_fn_to(),
},
v8::ExternalReference {
function: run_microtasks.map_fn_to(),
},
v8::ExternalReference {
function: has_tick_scheduled.map_fn_to(),
},
v8::ExternalReference {
function: set_has_tick_scheduled.map_fn_to(),
},
v8::ExternalReference {
function: eval_context.map_fn_to(),
},
v8::ExternalReference {
function: queue_microtask.map_fn_to(),
},
v8::ExternalReference {
function: create_host_object.map_fn_to(),
},
v8::ExternalReference {
function: encode.map_fn_to(),
},
v8::ExternalReference {
function: decode.map_fn_to(),
},
v8::ExternalReference {
function: serialize.map_fn_to(),
},
v8::ExternalReference {
function: deserialize.map_fn_to(),
},
v8::ExternalReference {
function: get_promise_details.map_fn_to(),
},
v8::ExternalReference {
function: get_proxy_details.map_fn_to(),
},
v8::ExternalReference {
function: is_proxy.map_fn_to(),
},
v8::ExternalReference {
function: memory_usage.map_fn_to(),
},
v8::ExternalReference {
function: call_console.map_fn_to(),
},
v8::ExternalReference {
function: set_wasm_streaming_callback.map_fn_to(),
},
];
let op_refs = ops
.iter()
.map(|(_, opref)| v8::ExternalReference { function: *opref });
refs.extend(op_refs);
let raw_op_state = Rc::as_ptr(&op_state) as *mut c_void;
refs.push(v8::ExternalReference {
pointer: raw_op_state,
});
v8::ExternalReferences::new(&refs)
}
pub fn script_origin<'a>(
s: &mut v8::HandleScope<'a>,
@ -154,6 +152,9 @@ pub fn module_origin<'a>(
pub fn initialize_context<'s>(
scope: &mut v8::HandleScope<'s, ()>,
ops: &[OpPair],
snapshot_loaded: bool,
op_state: Rc<RefCell<OpState>>,
) -> v8::Local<'s, v8::Context> {
let scope = &mut v8::EscapableHandleScope::new(scope);
@ -162,17 +163,43 @@ pub fn initialize_context<'s>(
let scope = &mut v8::ContextScope::new(scope, context);
// global.Deno = { core: {} };
let deno_key = v8::String::new(scope, "Deno").unwrap();
let core_key = v8::String::new(scope, "core").unwrap();
let ops_key = v8::String::new(scope, "ops").unwrap();
// Snapshot already registered `Deno.core.ops` but
// extensions may provide ops that aren't part of the snapshot.
//
// TODO(@littledivy): This is extra complexity for
// a really weird usecase. Remove this once all
// tsc ops are static at snapshot time.
if snapshot_loaded {
// Grab Deno.core.ops object
let deno_val = global.get(scope, deno_key.into()).unwrap();
let deno_val = v8::Local::<v8::Object>::try_from(deno_val)
.expect("`Deno` not in global scope.");
let core_val = deno_val.get(scope, core_key.into()).unwrap();
let core_val = v8::Local::<v8::Object>::try_from(core_val)
.expect("`Deno.core` not in global scope");
let ops_val = core_val.get(scope, ops_key.into()).unwrap();
let ops_val = v8::Local::<v8::Object>::try_from(ops_val)
.expect("`Deno.core.ops` not in global scope");
let raw_op_state = Rc::as_ptr(&op_state) as *const c_void;
for (name, opfn) in ops {
set_func_raw(scope, ops_val, name, *opfn, raw_op_state);
}
return scope.escape(context);
}
// global.Deno = { core: { ops: {} } };
let deno_val = v8::Object::new(scope);
global.set(scope, deno_key.into(), deno_val.into());
let core_key = v8::String::new(scope, "core").unwrap();
let core_val = v8::Object::new(scope);
deno_val.set(scope, core_key.into(), core_val.into());
let ops_val = v8::Object::new(scope);
core_val.set(scope, ops_key.into(), ops_val.into());
// Bind functions to Deno.core.*
set_func(scope, core_val, "opcallSync", opcall_sync);
set_func(scope, core_val, "opcallAsync", opcall_async);
set_func(scope, core_val, "refOp_", ref_op);
set_func(scope, core_val, "unrefOp_", unref_op);
set_func(
@ -227,10 +254,14 @@ pub fn initialize_context<'s>(
// Direct bindings on `window`.
set_func(scope, global, "queueMicrotask", queue_microtask);
// Bind functions to Deno.core.ops.*
let raw_op_state = Rc::as_ptr(&op_state) as *const c_void;
for (name, opfn) in ops {
set_func_raw(scope, ops_val, name, *opfn, raw_op_state);
}
scope.escape(context)
}
#[inline(always)]
pub fn set_func(
scope: &mut v8::HandleScope<'_>,
obj: v8::Local<v8::Object>,
@ -238,8 +269,26 @@ pub fn set_func(
callback: impl v8::MapFnTo<v8::FunctionCallback>,
) {
let key = v8::String::new(scope, name).unwrap();
let tmpl = v8::FunctionTemplate::new(scope, callback);
let val = tmpl.get_function(scope).unwrap();
let val = v8::Function::new(scope, callback).unwrap();
val.set_name(key);
obj.set(scope, key.into(), val.into());
}
// Register a raw v8::FunctionCallback
// with some external data.
pub fn set_func_raw(
scope: &mut v8::HandleScope<'_>,
obj: v8::Local<v8::Object>,
name: &'static str,
callback: v8::FunctionCallback,
external_data: *const c_void,
) {
let key = v8::String::new(scope, name).unwrap();
let external = v8::External::new(scope, external_data as *mut c_void);
let val = v8::Function::builder_raw(callback)
.data(external.into())
.build(scope)
.unwrap();
val.set_name(key);
obj.set(scope, key.into(), val.into());
}
@ -460,137 +509,6 @@ pub extern "C" fn promise_reject_callback(message: v8::PromiseRejectMessage) {
}
}
fn opcall_sync<'s>(
scope: &mut v8::HandleScope<'s>,
args: v8::FunctionCallbackArguments,
mut rv: v8::ReturnValue,
) {
let state_rc = JsRuntime::state(scope);
let state = state_rc.borrow_mut();
let op_id = match v8::Local::<v8::Integer>::try_from(args.get(0))
.map(|l| l.value() as OpId)
.map_err(Error::from)
{
Ok(op_id) => op_id,
Err(err) => {
let msg = if args.get(0).is_undefined() {
UNDEFINED_OP_ID_MSG.to_string()
} else {
format!("invalid op id: {}", err)
};
throw_type_error(scope, msg);
return;
}
};
// opcall(0) returns obj of all ops, handle as special case
if op_id == 0 {
// TODO: Serialize as HashMap when serde_v8 supports maps ...
let ops = OpTable::op_entries(state.op_state.clone());
rv.set(to_v8(scope, ops).unwrap());
return;
}
// Deserializable args (may be structured args or ZeroCopyBuf)
let a = args.get(1);
let b = args.get(2);
let payload = OpPayload {
scope,
a,
b,
op_id,
promise_id: 0,
};
let op = OpTable::route_op(op_id, state.op_state.clone(), payload);
match op {
Op::Sync(result) => {
state.op_state.borrow().tracker.track_sync(op_id);
rv.set(result.to_v8(scope).unwrap());
}
Op::NotFound => {
throw_type_error(scope, format!("Unknown op id: {}", op_id));
}
// Async ops (ref or unref)
_ => {
throw_type_error(
scope,
format!("Can not call an async op [{}] with opSync()", op_id),
);
}
}
}
fn opcall_async<'s>(
scope: &mut v8::HandleScope<'s>,
args: v8::FunctionCallbackArguments,
mut rv: v8::ReturnValue,
) {
let state_rc = JsRuntime::state(scope);
let mut state = state_rc.borrow_mut();
let op_id = match v8::Local::<v8::Integer>::try_from(args.get(0))
.map(|l| l.value() as OpId)
.map_err(Error::from)
{
Ok(op_id) => op_id,
Err(err) => {
let msg = if args.get(0).is_undefined() {
UNDEFINED_OP_ID_MSG.to_string()
} else {
format!("invalid op id: {}", err)
};
throw_type_error(scope, msg);
return;
}
};
// PromiseId
let arg1 = args.get(1);
let promise_id = v8::Local::<v8::Integer>::try_from(arg1)
.map(|l| l.value() as PromiseId)
.map_err(Error::from);
// Fail if promise id invalid (not an int)
let promise_id: PromiseId = match promise_id {
Ok(promise_id) => promise_id,
Err(err) => {
throw_type_error(scope, format!("invalid promise id: {}", err));
return;
}
};
// Deserializable args (may be structured args or ZeroCopyBuf)
let a = args.get(2);
let b = args.get(3);
let payload = OpPayload {
scope,
a,
b,
op_id,
promise_id,
};
let op = OpTable::route_op(op_id, state.op_state.clone(), payload);
match op {
Op::Sync(result) => match result {
OpResult::Ok(_) => throw_type_error(
scope,
format!("Can not call a sync op [{}] with opAsync()", op_id),
),
OpResult::Err(_) => rv.set(result.to_v8(scope).unwrap()),
},
Op::Async(fut) => {
state.op_state.borrow().tracker.track_async(op_id);
state.pending_ops.push(fut);
state.have_unpolled_ops = true;
}
Op::NotFound => {
throw_type_error(scope, format!("Unknown op id: {}", op_id));
}
}
}
fn ref_op<'s>(
scope: &mut v8::HandleScope<'s>,
args: v8::FunctionCallbackArguments,
@ -1471,7 +1389,7 @@ fn is_proxy(
rv.set(v8::Boolean::new(scope, args.get(0).is_proxy()).into())
}
fn throw_type_error(scope: &mut v8::HandleScope, message: impl AsRef<str>) {
pub fn throw_type_error(scope: &mut v8::HandleScope, message: impl AsRef<str>) {
let message = v8::String::new(scope, message.as_ref()).unwrap();
let exception = v8::Exception::type_error(scope, message);
scope.throw_exception(exception);

View file

@ -1,6 +1,6 @@
use anyhow::Error;
pub(crate) fn get_error_code(err: &Error) -> Option<&'static str> {
pub fn get_error_code(err: &Error) -> Option<&'static str> {
err
.downcast_ref::<std::io::Error>()
.map(|e| match e.raw_os_error() {

View file

@ -9,7 +9,7 @@ use deno_core::RuntimeOptions;
fn main() {
let my_ext = Extension::builder()
.middleware(|name, opfn| match name {
"op_print" => deno_core::void_op_sync(),
"op_print" => deno_core::void_op_sync::v8_cb(),
_ => opfn,
})
.build();

View file

@ -2,27 +2,37 @@
//! This example shows you how to define ops in Rust and then call them from
//! JavaScript.
use deno_core::op_sync;
use deno_core::op;
use deno_core::Extension;
use deno_core::JsRuntime;
use deno_core::OpState;
use deno_core::RuntimeOptions;
// This is a hack to make the `#[op]` macro work with
// deno_core examples.
// You can remove this:
use deno_core::*;
#[op]
fn op_sum(
_state: &mut OpState,
nums: Vec<f64>,
_: (),
) -> Result<f64, deno_core::error::AnyError> {
// Sum inputs
let sum = nums.iter().fold(0.0, |a, v| a + v);
// return as a Result<f64, AnyError>
Ok(sum)
}
fn main() {
// Build a deno_core::Extension providing custom ops
let ext = Extension::builder()
.ops(vec![
// An op for summing an array of numbers
(
"op_sum",
// The op-layer automatically deserializes inputs
// and serializes the returned Result & value
op_sync(|_state, nums: Vec<f64>, _: ()| {
// Sum inputs
let sum = nums.iter().fold(0.0, |a, v| a + v);
// return as a Result<f64, AnyError>
Ok(sum)
}),
),
// The op-layer automatically deserializes inputs
// and serializes the returned Result & value
op_sum::decl(),
])
.build();

View file

@ -11,12 +11,12 @@ const responseBuf = new Uint8Array(
/** Listens on 0.0.0.0:4500, returns rid. */
function listen() {
return Deno.core.opSync("listen");
return Deno.core.opSync("op_listen");
}
/** Accepts a connection, returns rid. */
function accept(serverRid) {
return Deno.core.opAsync("accept", serverRid);
return Deno.core.opAsync("op_accept", serverRid);
}
async function serve(rid) {

View file

@ -1,5 +1,6 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
use deno_core::anyhow::Error;
use deno_core::op;
use deno_core::AsyncRefCell;
use deno_core::AsyncResult;
use deno_core::CancelHandle;
@ -17,6 +18,11 @@ use std::rc::Rc;
use tokio::io::AsyncReadExt;
use tokio::io::AsyncWriteExt;
// This is a hack to make the `#[op]` macro work with
// deno_core examples.
// You can remove this:
use deno_core::*;
struct Logger;
impl log::Log for Logger {
@ -119,10 +125,7 @@ impl From<tokio::net::TcpStream> for TcpStream {
fn create_js_runtime() -> JsRuntime {
let ext = deno_core::Extension::builder()
.ops(vec![
("listen", deno_core::op_sync(op_listen)),
("accept", deno_core::op_async(op_accept)),
])
.ops(vec![op_listen::decl(), op_accept::decl()])
.build();
JsRuntime::new(deno_core::RuntimeOptions {
@ -131,6 +134,7 @@ fn create_js_runtime() -> JsRuntime {
})
}
#[op]
fn op_listen(state: &mut OpState, _: (), _: ()) -> Result<ResourceId, Error> {
log::debug!("listen");
let addr = "127.0.0.1:4544".parse::<SocketAddr>().unwrap();
@ -141,6 +145,7 @@ fn op_listen(state: &mut OpState, _: (), _: ()) -> Result<ResourceId, Error> {
Ok(rid)
}
#[op]
async fn op_accept(
state: Rc<RefCell<OpState>>,
rid: ResourceId,

View file

@ -1,6 +1,7 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
use deno_core::anyhow::Error;
use deno_core::op;
use deno_core::Extension;
use deno_core::JsRuntime;
use deno_core::OpState;
@ -9,14 +10,16 @@ use futures::channel::mpsc;
use futures::stream::StreamExt;
use std::task::Poll;
// This is a hack to make the `#[op]` macro work with
// deno_core examples.
// You can remove this:
use deno_core::*;
type Task = Box<dyn FnOnce()>;
fn main() {
let my_ext = Extension::builder()
.ops(vec![(
"op_schedule_task",
deno_core::op_sync(op_schedule_task),
)])
.ops(vec![op_schedule_task::decl()])
.event_loop_middleware(|state, cx| {
let recv = state.borrow_mut::<mpsc::UnboundedReceiver<Task>>();
let mut ref_loop = false;
@ -58,6 +61,7 @@ fn main() {
runtime.block_on(future).unwrap();
}
#[op]
fn op_schedule_task(state: &mut OpState, i: u8, _: ()) -> Result<(), Error> {
let tx = state.borrow_mut::<mpsc::UnboundedSender<Task>>();
tx.unbounded_send(Box::new(move || println!("Hello, world! x{}", i)))

View file

@ -1,12 +1,13 @@
use crate::OpFn;
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
use crate::OpState;
use anyhow::Error;
use std::task::Context;
pub type SourcePair = (&'static str, Box<SourceLoadFn>);
pub type SourceLoadFn = dyn Fn() -> Result<String, Error>;
pub type OpPair = (&'static str, Box<OpFn>);
pub type OpMiddlewareFn = dyn Fn(&'static str, Box<OpFn>) -> Box<OpFn>;
pub type OpFnRef = v8::FunctionCallback;
pub type OpPair = (&'static str, OpFnRef);
pub type OpMiddlewareFn = dyn Fn(&'static str, OpFnRef) -> OpFnRef;
pub type OpStateFn = dyn Fn(&mut OpState) -> Result<(), Error>;
pub type OpEventLoopFn = dyn Fn(&mut OpState, &mut Context) -> bool;
@ -108,7 +109,7 @@ impl ExtensionBuilder {
pub fn middleware<F>(&mut self, middleware_fn: F) -> &mut Self
where
F: Fn(&'static str, Box<OpFn>) -> Box<OpFn> + 'static,
F: Fn(&'static str, OpFnRef) -> OpFnRef + 'static,
{
self.middleware = Some(Box::new(middleware_fn));
self

View file

@ -13,7 +13,6 @@ mod modules;
mod normalize_path;
mod ops;
mod ops_builtin;
mod ops_json;
mod ops_metrics;
mod resources;
mod runtime;
@ -44,6 +43,10 @@ pub use crate::async_cell::AsyncRefCell;
pub use crate::async_cell::AsyncRefFuture;
pub use crate::async_cell::RcLike;
pub use crate::async_cell::RcRef;
pub use crate::extensions::Extension;
pub use crate::extensions::ExtensionBuilder;
pub use crate::extensions::OpMiddlewareFn;
pub use crate::extensions::OpPair;
pub use crate::flags::v8_set_flags;
pub use crate::inspector::InspectorMsg;
pub use crate::inspector::InspectorMsgKind;
@ -65,24 +68,21 @@ pub use crate::modules::ModuleSourceFuture;
pub use crate::modules::ModuleType;
pub use crate::modules::NoopModuleLoader;
pub use crate::normalize_path::normalize_path;
pub use crate::ops::serialize_op_result;
pub use crate::ops::Op;
pub use crate::ops::OpAsyncFuture;
pub use crate::ops::OpCall;
pub use crate::ops::OpError;
pub use crate::ops::OpFn;
pub use crate::ops::OpId;
pub use crate::ops::OpPayload;
pub use crate::ops::OpResult;
pub use crate::ops::OpState;
pub use crate::ops::OpTable;
pub use crate::ops::PromiseId;
pub use crate::ops_builtin::op_close;
pub use crate::ops_builtin::op_print;
pub use crate::ops_builtin::op_resources;
pub use crate::ops_json::op_async;
pub use crate::ops_json::op_sync;
pub use crate::ops_json::void_op_async;
pub use crate::ops_json::void_op_sync;
pub use crate::ops_builtin::void_op_async;
pub use crate::ops_builtin::void_op_sync;
pub use crate::ops_metrics::OpsTracker;
pub use crate::resources::AsyncResult;
pub use crate::resources::Resource;
pub use crate::resources::ResourceId;
@ -95,16 +95,21 @@ pub use crate::runtime::JsRuntime;
pub use crate::runtime::RuntimeOptions;
pub use crate::runtime::SharedArrayBufferStore;
pub use crate::runtime::Snapshot;
// pub use crate::runtime_modules::include_js_files!;
pub use crate::extensions::Extension;
pub use crate::extensions::ExtensionBuilder;
pub use crate::extensions::OpMiddlewareFn;
pub use crate::extensions::OpPair;
pub use deno_ops::op;
pub fn v8_version() -> &'static str {
v8::V8::get_version()
}
/// An internal module re-exporting funcs used by the #[op] (`deno_ops`) macro
#[doc(hidden)]
pub mod _ops {
pub use super::bindings::throw_type_error;
pub use super::error_codes::get_error_code;
pub use super::ops::to_op_result;
pub use super::runtime::queue_async_op;
}
/// A helper macro that will return a call site in Rust code. Should be
/// used when executing internal one-line scripts for JsRuntime lifecycle.
///

View file

@ -1073,13 +1073,11 @@ impl ModuleMap {
#[cfg(test)]
mod tests {
use super::*;
use crate::ops::OpCall;
use crate::serialize_op_result;
use crate::error::AnyError;
use crate::Extension;
use crate::JsRuntime;
use crate::Op;
use crate::OpPayload;
use crate::RuntimeOptions;
use deno_ops::op;
use futures::future::FutureExt;
use parking_lot::Mutex;
use std::fmt;
@ -1088,6 +1086,10 @@ mod tests {
use std::path::PathBuf;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
// deno_ops macros generate code assuming deno_core in scope.
mod deno_core {
pub use crate::*;
}
// TODO(ry) Sadly FuturesUnordered requires the current task to be set. So
// even though we are only using poll() in these tests and not Tokio, we must
@ -1401,20 +1403,16 @@ import "/a.js";
let loader = Rc::new(ModsLoader::default());
let resolve_count = loader.count.clone();
let dispatch_count = Arc::new(AtomicUsize::new(0));
let dispatch_count_ = dispatch_count.clone();
static DISPATCH_COUNT: AtomicUsize = AtomicUsize::new(0);
let op_test = move |state, payload: OpPayload| -> Op {
dispatch_count_.fetch_add(1, Ordering::Relaxed);
let (control, _): (u8, ()) = payload.deserialize().unwrap();
#[op]
fn op_test(_: &mut OpState, control: u8, _: ()) -> Result<u8, AnyError> {
DISPATCH_COUNT.fetch_add(1, Ordering::Relaxed);
assert_eq!(control, 42);
let resp = (0, 1, serialize_op_result(Ok(43), state));
Op::Async(OpCall::ready(resp))
};
Ok(43)
}
let ext = Extension::builder()
.ops(vec![("op_test", Box::new(op_test))])
.build();
let ext = Extension::builder().ops(vec![op_test::decl()]).build();
let mut runtime = JsRuntime::new(RuntimeOptions {
extensions: vec![ext],
@ -1435,7 +1433,7 @@ import "/a.js";
)
.unwrap();
assert_eq!(dispatch_count.load(Ordering::Relaxed), 0);
assert_eq!(DISPATCH_COUNT.load(Ordering::Relaxed), 0);
let module_map_rc = JsRuntime::module_map(runtime.v8_isolate());
@ -1452,12 +1450,12 @@ import "/a.js";
import { b } from './b.js'
if (b() != 'b') throw Error();
let control = 42;
Deno.core.opAsync("op_test", control);
Deno.core.opSync("op_test", control);
"#,
)
.unwrap();
assert_eq!(dispatch_count.load(Ordering::Relaxed), 0);
assert_eq!(DISPATCH_COUNT.load(Ordering::Relaxed), 0);
let imports = module_map.get_requested_modules(mod_a);
assert_eq!(
imports,
@ -1481,14 +1479,14 @@ import "/a.js";
};
runtime.instantiate_module(mod_b).unwrap();
assert_eq!(dispatch_count.load(Ordering::Relaxed), 0);
assert_eq!(DISPATCH_COUNT.load(Ordering::Relaxed), 0);
assert_eq!(resolve_count.load(Ordering::SeqCst), 1);
runtime.instantiate_module(mod_a).unwrap();
assert_eq!(dispatch_count.load(Ordering::Relaxed), 0);
assert_eq!(DISPATCH_COUNT.load(Ordering::Relaxed), 0);
let _ = runtime.mod_evaluate(mod_a);
assert_eq!(dispatch_count.load(Ordering::Relaxed), 1);
assert_eq!(DISPATCH_COUNT.load(Ordering::Relaxed), 1);
}
#[test]
@ -1766,7 +1764,6 @@ import "/a.js";
module_loader: Some(loader),
..Default::default()
});
runtime.sync_ops_cache();
runtime
.execute_script(
"file:///dyn_import3.js",

View file

@ -1,10 +1,9 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
use crate::error::type_error;
use crate::gotham_state::GothamState;
use crate::ops_metrics::OpsTracker;
use crate::resources::ResourceTable;
use crate::runtime::GetErrorClassFn;
use crate::OpsTracker;
use anyhow::Error;
use futures::future::maybe_done;
use futures::future::FusedFuture;
@ -12,23 +11,19 @@ use futures::future::MaybeDone;
use futures::ready;
use futures::task::noop_waker;
use futures::Future;
use indexmap::IndexMap;
use serde::de::DeserializeOwned;
use serde::Serialize;
use std::cell::RefCell;
use std::cell::UnsafeCell;
use std::iter::once;
use std::ops::Deref;
use std::ops::DerefMut;
use std::pin::Pin;
use std::rc::Rc;
use std::task::Context;
use std::task::Poll;
/// Wrapper around a Future, which causes that Future to be polled immediately.
/// (Background: ops are stored in a `FuturesUnordered` structure which polls
///
/// Background: ops are stored in a `FuturesUnordered` structure which polls
/// them, but without the `OpCall` wrapper this doesn't happen until the next
/// turn of the event loop, which is too late for certain ops.)
/// turn of the event loop, which is too late for certain ops.
pub struct OpCall<T>(MaybeDone<Pin<Box<dyn Future<Output = T>>>>);
impl<T> OpCall<T> {
@ -83,32 +78,10 @@ where
pub type PromiseId = i32;
pub type OpAsyncFuture = OpCall<(PromiseId, OpId, OpResult)>;
pub type OpFn = dyn Fn(Rc<RefCell<OpState>>, OpPayload) -> Op + 'static;
pub type OpFn =
fn(&mut v8::HandleScope, v8::FunctionCallbackArguments, v8::ReturnValue);
pub type OpId = usize;
pub struct OpPayload<'a, 'b, 'c> {
pub(crate) scope: &'a mut v8::HandleScope<'b>,
pub(crate) a: v8::Local<'c, v8::Value>,
pub(crate) b: v8::Local<'c, v8::Value>,
pub(crate) op_id: OpId,
pub(crate) promise_id: PromiseId,
}
impl<'a, 'b, 'c> OpPayload<'a, 'b, 'c> {
pub fn deserialize<T: DeserializeOwned, U: DeserializeOwned>(
self,
) -> Result<(T, U), Error> {
let a: T = serde_v8::from_v8(self.scope, self.a)
.map_err(Error::from)
.map_err(|e| type_error(format!("Error parsing args: {}", e)))?;
let b: U = serde_v8::from_v8(self.scope, self.b)
.map_err(Error::from)
.map_err(|e| type_error(format!("Error parsing args: {}", e)))?;
Ok((a, b))
}
}
pub enum Op {
Sync(OpResult),
Async(OpAsyncFuture),
@ -141,39 +114,43 @@ pub struct OpError {
code: Option<&'static str>,
}
pub fn serialize_op_result<R: Serialize + 'static>(
impl OpError {
pub fn new(get_class: GetErrorClassFn, err: Error) -> Self {
Self {
class_name: (get_class)(&err),
message: err.to_string(),
code: crate::error_codes::get_error_code(&err),
}
}
}
pub fn to_op_result<R: Serialize + 'static>(
get_class: GetErrorClassFn,
result: Result<R, Error>,
state: Rc<RefCell<OpState>>,
) -> OpResult {
match result {
Ok(v) => OpResult::Ok(v.into()),
Err(err) => OpResult::Err(OpError {
class_name: (state.borrow().get_error_class_fn)(&err),
message: err.to_string(),
code: crate::error_codes::get_error_code(&err),
}),
Err(err) => OpResult::Err(OpError::new(get_class, err)),
}
}
/// Maintains the resources and ops inside a JS runtime.
pub struct OpState {
pub resource_table: ResourceTable,
pub op_table: OpTable,
pub get_error_class_fn: GetErrorClassFn,
pub(crate) tracker: OpsTracker,
pub tracker: OpsTracker,
gotham_state: GothamState,
}
impl OpState {
pub(crate) fn new() -> OpState {
pub fn new(ops_count: usize) -> OpState {
OpState {
resource_table: Default::default(),
op_table: OpTable::default(),
get_error_class_fn: &|_| "Error",
tracker: OpsTracker {
ops: UnsafeCell::new(Vec::with_capacity(256)),
},
gotham_state: Default::default(),
tracker: OpsTracker {
ops: UnsafeCell::new(vec![Default::default(); ops_count]),
},
}
}
}
@ -191,81 +168,3 @@ impl DerefMut for OpState {
&mut self.gotham_state
}
}
/// Collection for storing registered ops. The special 'get_op_catalog'
/// op with OpId `0` is automatically added when the OpTable is created.
pub struct OpTable(IndexMap<String, Rc<OpFn>>);
impl OpTable {
pub fn register_op<F>(&mut self, name: &str, op_fn: F) -> OpId
where
F: Fn(Rc<RefCell<OpState>>, OpPayload) -> Op + 'static,
{
let (op_id, prev) = self.0.insert_full(name.to_owned(), Rc::new(op_fn));
assert!(prev.is_none());
op_id
}
pub fn op_entries(state: Rc<RefCell<OpState>>) -> Vec<(String, OpId)> {
state.borrow().op_table.0.keys().cloned().zip(0..).collect()
}
pub fn route_op(
op_id: OpId,
state: Rc<RefCell<OpState>>,
payload: OpPayload,
) -> Op {
let op_fn = state
.borrow()
.op_table
.0
.get_index(op_id)
.map(|(_, op_fn)| op_fn.clone());
match op_fn {
Some(f) => (f)(state, payload),
None => Op::NotFound,
}
}
}
impl Default for OpTable {
fn default() -> Self {
fn dummy(_state: Rc<RefCell<OpState>>, _p: OpPayload) -> Op {
unreachable!()
}
Self(once(("ops".to_owned(), Rc::new(dummy) as _)).collect())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn op_table() {
let state = Rc::new(RefCell::new(OpState::new()));
let foo_id;
let bar_id;
{
let op_table = &mut state.borrow_mut().op_table;
foo_id =
op_table.register_op("foo", |_, _| Op::Sync(OpResult::Ok(321.into())));
assert_eq!(foo_id, 1);
bar_id =
op_table.register_op("bar", |_, _| Op::Sync(OpResult::Ok(123.into())));
assert_eq!(bar_id, 2);
}
let mut catalog_entries = OpTable::op_entries(state);
catalog_entries.sort_by(|(_, id1), (_, id2)| id1.partial_cmp(id2).unwrap());
assert_eq!(
catalog_entries,
vec![
("ops".to_owned(), 0),
("foo".to_owned(), 1),
("bar".to_owned(), 2)
]
);
}
}

View file

@ -1,16 +1,13 @@
use crate::error::type_error;
use crate::include_js_files;
use crate::op_async;
use crate::op_sync;
use crate::ops_metrics::OpMetrics;
use crate::resources::ResourceId;
use crate::void_op_async;
use crate::void_op_sync;
use crate::Extension;
use crate::OpState;
use crate::Resource;
use crate::ZeroCopyBuf;
use anyhow::Error;
use deno_ops::op;
use std::cell::RefCell;
use std::io::{stderr, stdout, Write};
use std::rc::Rc;
@ -24,29 +21,40 @@ pub(crate) fn init_builtins() -> Extension {
"02_error.js",
))
.ops(vec![
("op_close", op_sync(op_close)),
("op_try_close", op_sync(op_try_close)),
("op_print", op_sync(op_print)),
("op_resources", op_sync(op_resources)),
("op_wasm_streaming_feed", op_sync(op_wasm_streaming_feed)),
("op_wasm_streaming_abort", op_sync(op_wasm_streaming_abort)),
(
"op_wasm_streaming_set_url",
op_sync(op_wasm_streaming_set_url),
),
("op_metrics", op_sync(op_metrics)),
("op_void_sync", void_op_sync()),
("op_void_async", void_op_async()),
// TODO(@AaronO): track IO metrics for builtin streams
("op_read", op_async(op_read)),
("op_write", op_async(op_write)),
("op_shutdown", op_async(op_shutdown)),
op_close::decl(),
op_try_close::decl(),
op_print::decl(),
op_resources::decl(),
op_wasm_streaming_feed::decl(),
op_wasm_streaming_abort::decl(),
op_wasm_streaming_set_url::decl(),
op_void_sync::decl(),
op_void_async::decl(),
// // TODO(@AaronO): track IO metrics for builtin streams
op_read::decl(),
op_write::decl(),
op_shutdown::decl(),
op_metrics::decl(),
])
.build()
}
#[op]
pub fn void_op_sync(_: &mut OpState, _: (), _: ()) -> Result<(), Error> {
Ok(())
}
pub async fn void_op_async(
_state: Rc<RefCell<OpState>>,
_: (),
_: (),
) -> Result<(), Error> {
Ok(())
}
/// Return map of resources with id as key
/// and string representation as value.
#[op]
pub fn op_resources(
state: &mut OpState,
_: (),
@ -60,7 +68,22 @@ pub fn op_resources(
Ok(serialized_resources)
}
#[op]
pub fn op_void_sync(_state: &mut OpState, _: (), _: ()) -> Result<(), Error> {
Ok(())
}
#[op]
pub async fn op_void_async(
_state: Rc<RefCell<OpState>>,
_: (),
_: (),
) -> Result<(), Error> {
Ok(())
}
/// Remove a resource from the resource table.
#[op]
pub fn op_close(
state: &mut OpState,
rid: Option<ResourceId>,
@ -75,6 +98,7 @@ pub fn op_close(
/// Try to remove a resource from the resource table. If there is no resource
/// with the specified `rid`, this is a no-op.
#[op]
pub fn op_try_close(
state: &mut OpState,
rid: Option<ResourceId>,
@ -87,7 +111,19 @@ pub fn op_try_close(
Ok(())
}
#[op]
pub fn op_metrics(
state: &mut OpState,
_: (),
_: (),
) -> Result<(OpMetrics, Vec<OpMetrics>), Error> {
let aggregate = state.tracker.aggregate();
let per_op = state.tracker.per_op();
Ok((aggregate, per_op))
}
/// Builtin utility to print to stdout/stderr
#[op]
pub fn op_print(
_state: &mut OpState,
msg: String,
@ -119,6 +155,7 @@ impl Resource for WasmStreamingResource {
}
/// Feed bytes to WasmStreamingResource.
#[op]
pub fn op_wasm_streaming_feed(
state: &mut OpState,
rid: ResourceId,
@ -133,6 +170,7 @@ pub fn op_wasm_streaming_feed(
}
/// Abort a WasmStreamingResource.
#[op]
pub fn op_wasm_streaming_abort(
state: &mut OpState,
rid: ResourceId,
@ -153,6 +191,7 @@ pub fn op_wasm_streaming_abort(
Ok(())
}
#[op]
pub fn op_wasm_streaming_set_url(
state: &mut OpState,
rid: ResourceId,
@ -166,16 +205,7 @@ pub fn op_wasm_streaming_set_url(
Ok(())
}
pub fn op_metrics(
state: &mut OpState,
_: (),
_: (),
) -> Result<(OpMetrics, Vec<OpMetrics>), Error> {
let aggregate = state.tracker.aggregate();
let per_op = state.tracker.per_op();
Ok((aggregate, per_op))
}
#[op]
async fn op_read(
state: Rc<RefCell<OpState>>,
rid: ResourceId,
@ -185,6 +215,7 @@ async fn op_read(
resource.read(buf).await.map(|n| n as u32)
}
#[op]
async fn op_write(
state: Rc<RefCell<OpState>>,
rid: ResourceId,
@ -194,6 +225,7 @@ async fn op_write(
resource.write(buf).await.map(|n| n as u32)
}
#[op]
async fn op_shutdown(
state: Rc<RefCell<OpState>>,
rid: ResourceId,

View file

@ -1,166 +0,0 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
use crate::ops::OpCall;
use crate::serialize_op_result;
use crate::Op;
use crate::OpFn;
use crate::OpState;
use anyhow::Error;
use serde::de::DeserializeOwned;
use serde::Serialize;
use std::cell::RefCell;
use std::future::Future;
use std::rc::Rc;
/// A helper function that returns a sync NOP OpFn
///
/// It's mainly intended for embedders who want to disable ops, see ./examples/disable_ops.rs
pub fn void_op_sync() -> Box<OpFn> {
op_sync(|_, _: (), _: ()| Ok(()))
}
/// A helper function that returns an async NOP OpFn
///
/// It's mainly intended for embedders who want to disable ops, see ./examples/disable_ops.rs
pub fn void_op_async() -> Box<OpFn> {
op_async(|_, _: (), _: ()| futures::future::ok(()))
}
/// Creates an op that passes data synchronously using JSON.
///
/// The provided function `op_fn` has the following parameters:
/// * `&mut OpState`: the op state, can be used to read/write resources in the runtime from an op.
/// * `V`: the deserializable value that is passed to the Rust function.
/// * `&mut [ZeroCopyBuf]`: raw bytes passed along, usually not needed if the JSON value is used.
///
/// `op_fn` returns a serializable value, which is directly returned to JavaScript.
///
/// When registering an op like this...
/// ```ignore
/// let mut runtime = JsRuntime::new(...);
/// runtime.register_op("hello", deno_core::op_sync(Self::hello_op));
/// runtime.sync_ops_cache();
/// ```
///
/// ...it can be invoked from JS using the provided name, for example:
/// ```js
/// let result = Deno.core.opSync("hello", args);
/// ```
///
/// `runtime.sync_ops_cache()` must be called after registering new ops
/// A more complete example is available in the examples directory.
pub fn op_sync<F, A, B, R>(op_fn: F) -> Box<OpFn>
where
F: Fn(&mut OpState, A, B) -> Result<R, Error> + 'static,
A: DeserializeOwned,
B: DeserializeOwned,
R: Serialize + 'static,
{
Box::new(move |state, payload| -> Op {
let result = payload
.deserialize()
.and_then(|(a, b)| op_fn(&mut state.borrow_mut(), a, b));
Op::Sync(serialize_op_result(result, state))
})
}
/// Creates an op that passes data asynchronously using JSON.
///
/// When this op is dispatched, the runtime doesn't exit while processing it.
///
/// The provided function `op_fn` has the following parameters:
/// * `Rc<RefCell<OpState>`: the op state, can be used to read/write resources in the runtime from an op.
/// * `V`: the deserializable value that is passed to the Rust function.
/// * `BufVec`: raw bytes passed along, usually not needed if the JSON value is used.
///
/// `op_fn` returns a future, whose output is a serializable value. This value will be asynchronously
/// returned to JavaScript.
///
/// When registering an op like this...
/// ```ignore
/// let mut runtime = JsRuntime::new(...);
/// runtime.register_op("hello", deno_core::op_async(Self::hello_op));
/// runtime.sync_ops_cache();
/// ```
///
/// ...it can be invoked from JS using the provided name, for example:
/// ```js
/// let future = Deno.core.opAsync("hello", args);
/// ```
///
/// `runtime.sync_ops_cache()` must be called after registering new ops
/// A more complete example is available in the examples directory.
pub fn op_async<F, A, B, R, RV>(op_fn: F) -> Box<OpFn>
where
F: Fn(Rc<RefCell<OpState>>, A, B) -> R + 'static,
A: DeserializeOwned,
B: DeserializeOwned,
R: Future<Output = Result<RV, Error>> + 'static,
RV: Serialize + 'static,
{
Box::new(move |state, payload| -> Op {
let op_id = payload.op_id;
let pid = payload.promise_id;
// Deserialize args, sync error on failure
let args = match payload.deserialize() {
Ok(args) => args,
Err(err) => {
return Op::Sync(serialize_op_result(Err::<(), Error>(err), state))
}
};
let (a, b) = args;
use crate::futures::FutureExt;
let fut = op_fn(state.clone(), a, b)
.map(move |result| (pid, op_id, serialize_op_result(result, state)));
Op::Async(OpCall::eager(fut))
})
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn op_async_stack_trace() {
async fn op_throw(
_state: Rc<RefCell<OpState>>,
msg: Option<String>,
_: (),
) -> Result<(), Error> {
assert_eq!(msg.unwrap(), "hello");
Err(crate::error::generic_error("foo"))
}
let ext = crate::Extension::builder()
.ops(vec![("op_throw", op_async(op_throw))])
.build();
let mut runtime = crate::JsRuntime::new(crate::RuntimeOptions {
extensions: vec![ext],
..Default::default()
});
runtime
.execute_script(
"<init>",
r#"
async function f1() {
await Deno.core.opAsync('op_throw', 'hello');
}
async function f2() {
await f1();
}
f2();
"#,
)
.unwrap();
let e = runtime.run_event_loop(false).await.unwrap_err().to_string();
println!("{}", e);
assert!(e.contains("Error: foo"));
assert!(e.contains("at async f1 (<init>:"));
assert!(e.contains("at async f2 (<init>:"));
}
}

View file

@ -59,20 +59,10 @@ impl OpsTracker {
unsafe { &mut *self.ops.get() }
}
#[inline]
fn ensure_capacity(ops: &mut Vec<OpMetrics>, op_id: OpId) {
if op_id >= ops.len() {
ops.resize(1 + op_id, OpMetrics::default())
}
}
#[allow(clippy::mut_from_ref)]
#[inline]
fn metrics_mut(&self, id: OpId) -> &mut OpMetrics {
let ops = self.ops_mut();
// TODO(@AaronO): Pre-alloc capacity at runtime init once we forbid post-boot op registrations
Self::ensure_capacity(ops, id);
unsafe { ops.get_unchecked_mut(id) }
unsafe { self.ops_mut().get_unchecked_mut(id) }
}
#[inline]

View file

@ -6,6 +6,7 @@ use crate::error::generic_error;
use crate::error::ErrWithV8Handle;
use crate::error::JsError;
use crate::extensions::OpEventLoopFn;
use crate::extensions::OpPair;
use crate::inspector::JsRuntimeInspector;
use crate::module_specifier::ModuleSpecifier;
use crate::modules::ModuleId;
@ -16,13 +17,13 @@ use crate::modules::NoopModuleLoader;
use crate::ops::*;
use crate::Extension;
use crate::OpMiddlewareFn;
use crate::OpPayload;
use crate::OpResult;
use crate::OpState;
use crate::PromiseId;
use anyhow::Error;
use futures::channel::oneshot;
use futures::future::poll_fn;
use futures::future::Future;
use futures::future::FutureExt;
use futures::stream::FuturesUnordered;
use futures::stream::StreamExt;
@ -143,7 +144,6 @@ pub type CompiledWasmModuleStore = CrossIsolateStore<v8::CompiledWasmModule>;
pub(crate) struct JsRuntimeState {
pub global_context: Option<v8::Global<v8::Context>>,
pub(crate) js_recv_cb: Option<v8::Global<v8::Function>>,
pub(crate) js_sync_cb: Option<v8::Global<v8::Function>>,
pub(crate) js_macrotask_cbs: Vec<v8::Global<v8::Function>>,
pub(crate) js_nexttick_cbs: Vec<v8::Global<v8::Function>>,
pub(crate) js_promise_reject_cb: Option<v8::Global<v8::Function>>,
@ -279,17 +279,37 @@ impl JsRuntime {
let has_startup_snapshot = options.startup_snapshot.is_some();
let js_error_create_fn = options
.js_error_create_fn
.unwrap_or_else(|| Rc::new(JsError::create));
// Add builtins extension
options
.extensions
.insert(0, crate::ops_builtin::init_builtins());
let ops = Self::collect_ops(&mut options.extensions);
let mut op_state = OpState::new(ops.len());
if let Some(get_error_class_fn) = options.get_error_class_fn {
op_state.get_error_class_fn = get_error_class_fn;
}
let op_state = Rc::new(RefCell::new(op_state));
let refs = bindings::external_references(&ops, op_state.clone());
let refs: &'static v8::ExternalReferences = Box::leak(Box::new(refs));
let global_context;
let (mut isolate, maybe_snapshot_creator) = if options.will_snapshot {
// TODO(ry) Support loading snapshots before snapshotting.
assert!(options.startup_snapshot.is_none());
let mut creator =
v8::SnapshotCreator::new(Some(&bindings::EXTERNAL_REFERENCES));
let mut creator = v8::SnapshotCreator::new(Some(refs));
let isolate = unsafe { creator.get_owned_isolate() };
let mut isolate = JsRuntime::setup_isolate(isolate);
{
let scope = &mut v8::HandleScope::new(&mut isolate);
let context = bindings::initialize_context(scope);
let context =
bindings::initialize_context(scope, &ops, false, op_state.clone());
global_context = v8::Global::new(scope, context);
creator.set_default_context(context);
}
@ -299,7 +319,7 @@ impl JsRuntime {
.create_params
.take()
.unwrap_or_else(v8::Isolate::create_params)
.external_references(&**bindings::EXTERNAL_REFERENCES);
.external_references(&**refs);
let snapshot_loaded = if let Some(snapshot) = options.startup_snapshot {
params = match snapshot {
Snapshot::Static(data) => params.snapshot_blob(data),
@ -315,13 +335,13 @@ impl JsRuntime {
let mut isolate = JsRuntime::setup_isolate(isolate);
{
let scope = &mut v8::HandleScope::new(&mut isolate);
let context = if snapshot_loaded {
v8::Context::new(scope)
} else {
// If no snapshot is provided, we initialize the context with empty
// main source code and source maps.
bindings::initialize_context(scope)
};
let context = bindings::initialize_context(
scope,
&ops,
snapshot_loaded,
op_state.clone(),
);
global_context = v8::Global::new(scope, context);
}
(isolate, None)
@ -334,17 +354,6 @@ impl JsRuntime {
.module_loader
.unwrap_or_else(|| Rc::new(NoopModuleLoader));
let js_error_create_fn = options
.js_error_create_fn
.unwrap_or_else(|| Rc::new(JsError::create));
let mut op_state = OpState::new();
if let Some(get_error_class_fn) = options.get_error_class_fn {
op_state.get_error_class_fn = get_error_class_fn;
}
let op_state = Rc::new(RefCell::new(op_state));
isolate.set_slot(Rc::new(RefCell::new(JsRuntimeState {
global_context: Some(global_context),
pending_promise_exceptions: HashMap::new(),
@ -352,7 +361,6 @@ impl JsRuntime {
pending_mod_evaluate: None,
dyn_module_evaluate_idle_counter: 0,
js_recv_cb: None,
js_sync_cb: None,
js_macrotask_cbs: vec![],
js_nexttick_cbs: vec![],
js_promise_reject_cb: None,
@ -372,11 +380,6 @@ impl JsRuntime {
let module_map = ModuleMap::new(loader, op_state);
isolate.set_slot(Rc::new(RefCell::new(module_map)));
// Add builtins extension
options
.extensions
.insert(0, crate::ops_builtin::init_builtins());
let mut js_runtime = Self {
v8_isolate: Some(isolate),
inspector: Some(inspector),
@ -394,10 +397,8 @@ impl JsRuntime {
}
// Init extension ops
js_runtime.init_extension_ops().unwrap();
// Init callbacks (opresolve & syncOpsCache)
// Init callbacks (opresolve)
js_runtime.init_cbs();
// Sync ops cache
js_runtime.sync_ops_cache();
js_runtime
}
@ -461,34 +462,44 @@ impl JsRuntime {
Ok(())
}
/// Collects ops from extensions & applies middleware
fn collect_ops(extensions: &mut [Extension]) -> Vec<OpPair> {
// Middleware
let middleware: Vec<Box<OpMiddlewareFn>> = extensions
.iter_mut()
.filter_map(|e| e.init_middleware())
.collect();
// macroware wraps an opfn in all the middleware
let macroware =
move |name, opfn| middleware.iter().fold(opfn, |opfn, m| m(name, opfn));
// Flatten ops & apply middlware
extensions
.iter_mut()
.filter_map(|e| e.init_ops())
.flatten()
.map(|(name, opfn)| (name, macroware(name, opfn)))
.collect()
}
/// Initializes ops of provided Extensions
fn init_extension_ops(&mut self) -> Result<(), Error> {
let op_state = self.op_state();
// Take extensions to avoid double-borrow
let mut extensions: Vec<Extension> = std::mem::take(&mut self.extensions);
// Middleware
let middleware: Vec<Box<OpMiddlewareFn>> = extensions
.iter_mut()
.filter_map(|e| e.init_middleware())
.collect();
// macroware wraps an opfn in all the middleware
let macroware =
move |name, opfn| middleware.iter().fold(opfn, |opfn, m| m(name, opfn));
// Register ops
// Setup state
for e in extensions.iter_mut() {
// ops are already registered during in bindings::initialize_context();
e.init_state(&mut op_state.borrow_mut())?;
// Register each op after middlewaring it
let ops = e.init_ops().unwrap_or_default();
for (name, opfn) in ops {
self.register_op(name, macroware(name, opfn));
}
// Setup event-loop middleware
if let Some(middleware) = e.init_event_loop_middleware() {
self.event_loop_middlewares.push(middleware);
}
}
// Restore extensions
self.extensions = extensions;
@ -511,22 +522,10 @@ impl JsRuntime {
fn init_cbs(&mut self) {
let mut scope = self.handle_scope();
let recv_cb = Self::grab_fn(&mut scope, "Deno.core.opresolve");
let sync_cb = Self::grab_fn(&mut scope, "Deno.core.syncOpsCache");
// Put global handles in state
let state_rc = JsRuntime::state(&scope);
let mut state = state_rc.borrow_mut();
state.js_recv_cb.replace(recv_cb);
state.js_sync_cb.replace(sync_cb);
}
/// Ensures core.js has the latest op-name to op-id mappings
pub fn sync_ops_cache(&mut self) {
let scope = &mut self.handle_scope();
let state_rc = JsRuntime::state(scope);
let js_sync_cb_handle = state_rc.borrow().js_sync_cb.clone().unwrap();
let js_sync_cb = js_sync_cb_handle.open(scope);
let this = v8::undefined(scope).into();
js_sync_cb.call(scope, this, &[]);
}
/// Returns the runtime's op state, which can be used to maintain ops
@ -612,7 +611,6 @@ impl JsRuntime {
))));
// Drop other v8::Global handles before snapshotting
std::mem::take(&mut state.borrow_mut().js_recv_cb);
std::mem::take(&mut state.borrow_mut().js_sync_cb);
let snapshot_creator = self.snapshot_creator.as_mut().unwrap();
let snapshot = snapshot_creator
@ -623,27 +621,6 @@ impl JsRuntime {
snapshot
}
/// Registers an op that can be called from JavaScript.
///
/// The _op_ mechanism allows to expose Rust functions to the JS runtime,
/// which can be called using the provided `name`.
///
/// This function provides byte-level bindings. To pass data via JSON, the
/// following functions can be passed as an argument for `op_fn`:
/// * [op_sync()](fn.op_sync.html)
/// * [op_async()](fn.op_async.html)
pub fn register_op<F>(&mut self, name: &str, op_fn: F) -> OpId
where
F: Fn(Rc<RefCell<OpState>>, OpPayload) -> Op + 'static,
{
Self::state(self.v8_isolate())
.borrow_mut()
.op_state
.borrow_mut()
.op_table
.register_op(name, op_fn)
}
/// Registers a callback on the isolate when the memory limits are approached.
/// Use this to prevent V8 from crashing the process when reaching the limit.
///
@ -1552,13 +1529,11 @@ impl JsRuntime {
let mut state = state_rc.borrow_mut();
state.have_unpolled_ops = false;
let op_state = state.op_state.clone();
while let Poll::Ready(Some(item)) = state.pending_ops.poll_next_unpin(cx)
{
let (promise_id, op_id, resp) = item;
op_state.borrow().tracker.track_async_completed(op_id);
state.unrefed_ops.remove(&promise_id);
state.op_state.borrow().tracker.track_async_completed(op_id);
args.push(v8::Integer::new(scope, promise_id as i32).into());
args.push(resp.to_v8(scope).unwrap());
}
@ -1654,22 +1629,37 @@ impl JsRuntime {
}
}
#[inline]
pub fn queue_async_op(
scope: &v8::Isolate,
op: impl Future<Output = (PromiseId, OpId, OpResult)> + 'static,
) {
let state_rc = JsRuntime::state(scope);
let mut state = state_rc.borrow_mut();
state.pending_ops.push(OpCall::eager(op));
state.have_unpolled_ops = true;
}
#[cfg(test)]
pub mod tests {
use super::*;
use crate::error::custom_error;
use crate::error::AnyError;
use crate::modules::ModuleSource;
use crate::modules::ModuleSourceFuture;
use crate::modules::ModuleType;
use crate::op_async;
use crate::op_sync;
use crate::ZeroCopyBuf;
use deno_ops::op;
use futures::future::lazy;
use std::ops::FnOnce;
use std::pin::Pin;
use std::rc::Rc;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
// deno_ops macros generate code assuming deno_core in scope.
mod deno_core {
pub use crate::*;
}
pub fn run_in_task<F>(f: F)
where
@ -1689,26 +1679,26 @@ pub mod tests {
dispatch_count: Arc<AtomicUsize>,
}
fn op_test(rc_op_state: Rc<RefCell<OpState>>, payload: OpPayload) -> Op {
let rc_op_state2 = rc_op_state.clone();
let op_state_ = rc_op_state2.borrow();
#[op]
async fn op_test(
rc_op_state: Rc<RefCell<OpState>>,
control: u8,
buf: Option<ZeroCopyBuf>,
) -> Result<u8, AnyError> {
let op_state_ = rc_op_state.borrow();
let test_state = op_state_.borrow::<TestState>();
test_state.dispatch_count.fetch_add(1, Ordering::Relaxed);
let (control, buf): (u8, Option<ZeroCopyBuf>) =
payload.deserialize().unwrap();
match test_state.mode {
Mode::Async => {
assert_eq!(control, 42);
let resp = (0, 1, serialize_op_result(Ok(43), rc_op_state));
Op::Async(OpCall::ready(resp))
Ok(43)
}
Mode::AsyncZeroCopy(has_buffer) => {
assert_eq!(buf.is_some(), has_buffer);
if let Some(buf) = buf {
assert_eq!(buf.len(), 1);
}
let resp = (0, 1, serialize_op_result(Ok(43), rc_op_state));
Op::Async(OpCall::ready(resp))
Ok(43)
}
}
}
@ -1717,7 +1707,7 @@ pub mod tests {
let dispatch_count = Arc::new(AtomicUsize::new(0));
let dispatch_count2 = dispatch_count.clone();
let ext = Extension::builder()
.ops(vec![("op_test", Box::new(op_test))])
.ops(vec![op_test::decl()])
.state(move |state| {
state.put(TestState {
mode,
@ -2027,30 +2017,6 @@ pub mod tests {
v8_isolate_handle.terminate_execution();
}
#[test]
fn test_pre_dispatch() {
run_in_task(|cx| {
let (mut runtime, _dispatch_count) = setup(Mode::Async);
runtime
.execute_script(
"bad_op_id.js",
r#"
let thrown;
try {
Deno.core.opcallSync(100, null, null);
} catch (e) {
thrown = e;
}
assert(String(thrown) === "TypeError: Unknown op id: 100");
"#,
)
.unwrap();
if let Poll::Ready(Err(_)) = runtime.poll_event_loop(cx, false) {
unreachable!();
}
});
}
#[test]
fn syntax_error() {
let mut runtime = JsRuntime::new(Default::default());
@ -2095,6 +2061,7 @@ pub mod tests {
#[test]
fn test_error_builder() {
#[op]
fn op_err(_: &mut OpState, _: (), _: ()) -> Result<(), Error> {
Err(custom_error("DOMExceptionOperationError", "abc"))
}
@ -2104,9 +2071,7 @@ pub mod tests {
}
run_in_task(|cx| {
let ext = Extension::builder()
.ops(vec![("op_err", op_sync(op_err))])
.build();
let ext = Extension::builder().ops(vec![op_err::decl()]).build();
let mut runtime = JsRuntime::new(RuntimeOptions {
extensions: vec![ext],
get_error_class_fn: Some(&get_error_class_name),
@ -2177,7 +2142,7 @@ pub mod tests {
});
let cb_handle = runtime.v8_isolate().thread_safe_handle();
let callback_invoke_count = Rc::new(AtomicUsize::default());
let callback_invoke_count = Rc::new(AtomicUsize::new(0));
let inner_invoke_count = Rc::clone(&callback_invoke_count);
runtime.add_near_heap_limit_callback(
@ -2221,7 +2186,7 @@ pub mod tests {
});
let cb_handle = runtime.v8_isolate().thread_safe_handle();
let callback_invoke_count_first = Rc::new(AtomicUsize::default());
let callback_invoke_count_first = Rc::new(AtomicUsize::new(0));
let inner_invoke_count_first = Rc::clone(&callback_invoke_count_first);
runtime.add_near_heap_limit_callback(
move |current_limit, _initial_limit| {
@ -2230,7 +2195,7 @@ pub mod tests {
},
);
let callback_invoke_count_second = Rc::new(AtomicUsize::default());
let callback_invoke_count_second = Rc::new(AtomicUsize::new(0));
let inner_invoke_count_second = Rc::clone(&callback_invoke_count_second);
runtime.add_near_heap_limit_callback(
move |current_limit, _initial_limit| {
@ -2500,6 +2465,7 @@ assertEquals(1, notify_return_value);
async fn test_async_opstate_borrow() {
struct InnerState(u64);
#[op]
async fn op_async_borrow(
op_state: Rc<RefCell<OpState>>,
_: (),
@ -2519,7 +2485,7 @@ assertEquals(1, notify_return_value);
}
let extension = Extension::builder()
.ops(vec![("op_async_borrow", op_async(op_async_borrow))])
.ops(vec![op_async_borrow::decl()])
.state(|state| {
state.put(InnerState(42));
Ok(())
@ -2542,6 +2508,7 @@ assertEquals(1, notify_return_value);
#[tokio::test]
async fn test_set_macrotask_callback_set_next_tick_callback() {
#[op]
async fn op_async_sleep(
_op_state: Rc<RefCell<OpState>>,
_: (),
@ -2553,7 +2520,7 @@ assertEquals(1, notify_return_value);
}
let extension = Extension::builder()
.ops(vec![("op_async_sleep", op_async(op_async_sleep))])
.ops(vec![op_async_sleep::decl()])
.build();
let mut runtime = JsRuntime::new(RuntimeOptions {
@ -2617,25 +2584,23 @@ assertEquals(1, notify_return_value);
fn test_has_tick_scheduled() {
use futures::task::ArcWake;
let macrotask = Arc::new(AtomicUsize::default());
let macrotask_ = Arc::clone(&macrotask);
static MACROTASK: AtomicUsize = AtomicUsize::new(0);
static NEXT_TICK: AtomicUsize = AtomicUsize::new(0);
let next_tick = Arc::new(AtomicUsize::default());
let next_tick_ = Arc::clone(&next_tick);
let op_macrotask = move |_: &mut OpState, _: (), _: ()| {
macrotask_.fetch_add(1, Ordering::Relaxed);
#[op]
fn op_macrotask(_: &mut OpState, _: (), _: ()) -> Result<(), AnyError> {
MACROTASK.fetch_add(1, Ordering::Relaxed);
Ok(())
};
}
let op_next_tick = move |_: &mut OpState, _: (), _: ()| {
next_tick_.fetch_add(1, Ordering::Relaxed);
#[op]
fn op_next_tick(_: &mut OpState, _: (), _: ()) -> Result<(), AnyError> {
NEXT_TICK.fetch_add(1, Ordering::Relaxed);
Ok(())
};
}
let extension = Extension::builder()
.ops(vec![("op_macrotask", op_sync(op_macrotask))])
.ops(vec![("op_next_tick", op_sync(op_next_tick))])
.ops(vec![op_macrotask::decl(), op_next_tick::decl()])
.build();
let mut runtime = JsRuntime::new(RuntimeOptions {
@ -2670,8 +2635,8 @@ assertEquals(1, notify_return_value);
let cx = &mut Context::from_waker(&waker);
assert!(matches!(runtime.poll_event_loop(cx, false), Poll::Pending));
assert_eq!(1, macrotask.load(Ordering::Relaxed));
assert_eq!(1, next_tick.load(Ordering::Relaxed));
assert_eq!(1, MACROTASK.load(Ordering::Relaxed));
assert_eq!(1, NEXT_TICK.load(Ordering::Relaxed));
assert_eq!(awoken_times.swap(0, Ordering::Relaxed), 1);
assert!(matches!(runtime.poll_event_loop(cx, false), Poll::Pending));
assert_eq!(awoken_times.swap(0, Ordering::Relaxed), 1);
@ -2756,28 +2721,34 @@ assertEquals(1, notify_return_value);
#[tokio::test]
async fn test_set_promise_reject_callback() {
let promise_reject = Arc::new(AtomicUsize::default());
let promise_reject_ = Arc::clone(&promise_reject);
static PROMISE_REJECT: AtomicUsize = AtomicUsize::new(0);
static UNCAUGHT_EXCEPTION: AtomicUsize = AtomicUsize::new(0);
let uncaught_exception = Arc::new(AtomicUsize::default());
let uncaught_exception_ = Arc::clone(&uncaught_exception);
let op_promise_reject = move |_: &mut OpState, _: (), _: ()| {
promise_reject_.fetch_add(1, Ordering::Relaxed);
#[op]
fn op_promise_reject(
_: &mut OpState,
_: (),
_: (),
) -> Result<(), AnyError> {
PROMISE_REJECT.fetch_add(1, Ordering::Relaxed);
Ok(())
};
}
let op_uncaught_exception = move |_: &mut OpState, _: (), _: ()| {
uncaught_exception_.fetch_add(1, Ordering::Relaxed);
#[op]
fn op_uncaught_exception(
_: &mut OpState,
_: (),
_: (),
) -> Result<(), AnyError> {
UNCAUGHT_EXCEPTION.fetch_add(1, Ordering::Relaxed);
Ok(())
};
}
let extension = Extension::builder()
.ops(vec![("op_promise_reject", op_sync(op_promise_reject))])
.ops(vec![(
"op_uncaught_exception",
op_sync(op_uncaught_exception),
)])
.ops(vec![
op_promise_reject::decl(),
op_uncaught_exception::decl(),
])
.build();
let mut runtime = JsRuntime::new(RuntimeOptions {
@ -2812,8 +2783,8 @@ assertEquals(1, notify_return_value);
.unwrap();
runtime.run_event_loop(false).await.unwrap();
assert_eq!(1, promise_reject.load(Ordering::Relaxed));
assert_eq!(1, uncaught_exception.load(Ordering::Relaxed));
assert_eq!(1, PROMISE_REJECT.load(Ordering::Relaxed));
assert_eq!(1, UNCAUGHT_EXCEPTION.load(Ordering::Relaxed));
runtime
.execute_script(
@ -2840,7 +2811,7 @@ assertEquals(1, notify_return_value);
// printed to stderr.
runtime.run_event_loop(false).await.unwrap();
assert_eq!(2, promise_reject.load(Ordering::Relaxed));
assert_eq!(2, uncaught_exception.load(Ordering::Relaxed));
assert_eq!(2, PROMISE_REJECT.load(Ordering::Relaxed));
assert_eq!(2, UNCAUGHT_EXCEPTION.load(Ordering::Relaxed));
}
}

View file

@ -8,8 +8,7 @@ pub use in_memory_broadcast_channel::InMemoryBroadcastChannelResource;
use async_trait::async_trait;
use deno_core::error::AnyError;
use deno_core::include_js_files;
use deno_core::op_async;
use deno_core::op_sync;
use deno_core::op;
use deno_core::Extension;
use deno_core::OpState;
use deno_core::Resource;
@ -43,11 +42,15 @@ pub type Message = (String, Vec<u8>);
struct Unstable(bool); // --unstable
pub fn op_broadcast_subscribe<BC: BroadcastChannel + 'static>(
#[op]
pub fn op_broadcast_subscribe<BC>(
state: &mut OpState,
_: (),
_: (),
) -> Result<ResourceId, AnyError> {
) -> Result<ResourceId, AnyError>
where
BC: BroadcastChannel + 'static,
{
let unstable = state.borrow::<Unstable>().0;
if !unstable {
@ -62,31 +65,43 @@ pub fn op_broadcast_subscribe<BC: BroadcastChannel + 'static>(
Ok(state.resource_table.add(resource))
}
pub fn op_broadcast_unsubscribe<BC: BroadcastChannel + 'static>(
#[op]
pub fn op_broadcast_unsubscribe<BC>(
state: &mut OpState,
rid: ResourceId,
_buf: (),
) -> Result<(), AnyError> {
) -> Result<(), AnyError>
where
BC: BroadcastChannel + 'static,
{
let resource = state.resource_table.get::<BC::Resource>(rid)?;
let bc = state.borrow::<BC>();
bc.unsubscribe(&resource)
}
pub async fn op_broadcast_send<BC: BroadcastChannel + 'static>(
#[op]
pub async fn op_broadcast_send<BC>(
state: Rc<RefCell<OpState>>,
(rid, name): (ResourceId, String),
buf: ZeroCopyBuf,
) -> Result<(), AnyError> {
) -> Result<(), AnyError>
where
BC: BroadcastChannel + 'static,
{
let resource = state.borrow().resource_table.get::<BC::Resource>(rid)?;
let bc = state.borrow().borrow::<BC>().clone();
bc.send(&resource, name, buf.to_vec()).await
}
pub async fn op_broadcast_recv<BC: BroadcastChannel + 'static>(
#[op]
pub async fn op_broadcast_recv<BC>(
state: Rc<RefCell<OpState>>,
rid: ResourceId,
_: (),
) -> Result<Option<Message>, AnyError> {
) -> Result<Option<Message>, AnyError>
where
BC: BroadcastChannel + 'static,
{
let resource = state.borrow().resource_table.get::<BC::Resource>(rid)?;
let bc = state.borrow().borrow::<BC>().clone();
bc.recv(&resource).await
@ -102,16 +117,10 @@ pub fn init<BC: BroadcastChannel + 'static>(
"01_broadcast_channel.js",
))
.ops(vec![
(
"op_broadcast_subscribe",
op_sync(op_broadcast_subscribe::<BC>),
),
(
"op_broadcast_unsubscribe",
op_sync(op_broadcast_unsubscribe::<BC>),
),
("op_broadcast_send", op_async(op_broadcast_send::<BC>)),
("op_broadcast_recv", op_async(op_broadcast_recv::<BC>)),
op_broadcast_subscribe::decl::<BC>(),
op_broadcast_unsubscribe::decl::<BC>(),
op_broadcast_send::decl::<BC>(),
op_broadcast_recv::decl::<BC>(),
])
.state(move |state| {
state.put(bc.clone());

View file

@ -24,6 +24,7 @@ use ctr::Ctr;
use deno_core::error::custom_error;
use deno_core::error::type_error;
use deno_core::error::AnyError;
use deno_core::op;
use deno_core::OpState;
use deno_core::ZeroCopyBuf;
use rsa::pkcs1::FromRsaPrivateKey;
@ -76,6 +77,7 @@ pub enum DecryptAlgorithm {
},
}
#[op]
pub async fn op_crypto_decrypt(
_state: Rc<RefCell<OpState>>,
opts: DecryptOptions,

View file

@ -16,6 +16,7 @@ use aes_gcm::AeadInPlace;
use aes_gcm::NewAead;
use aes_gcm::Nonce;
use ctr::Ctr;
use deno_core::op;
use block_modes::BlockMode;
use ctr::cipher::StreamCipher;
@ -79,6 +80,8 @@ pub enum EncryptAlgorithm {
key_length: usize,
},
}
#[op]
pub async fn op_crypto_encrypt(
_state: Rc<RefCell<OpState>>,
opts: EncryptOptions,

View file

@ -1,5 +1,6 @@
use deno_core::error::custom_error;
use deno_core::error::AnyError;
use deno_core::op;
use deno_core::OpState;
use deno_core::ZeroCopyBuf;
use rsa::pkcs1::UIntBytes;
@ -84,6 +85,7 @@ pub enum ExportKeyResult {
},
}
#[op]
pub fn op_crypto_export_key(
_state: &mut OpState,
opts: ExportKeyOptions,

View file

@ -3,6 +3,7 @@ use std::rc::Rc;
use crate::shared::*;
use deno_core::error::AnyError;
use deno_core::op;
use deno_core::OpState;
use deno_core::ZeroCopyBuf;
use elliptic_curve::rand_core::OsRng;
@ -41,6 +42,7 @@ pub enum GenerateKeyOptions {
},
}
#[op]
pub async fn op_crypto_generate_key(
_state: Rc<RefCell<OpState>>,
opts: GenerateKeyOptions,

View file

@ -1,4 +1,5 @@
use deno_core::error::AnyError;
use deno_core::op;
use deno_core::OpState;
use deno_core::ZeroCopyBuf;
use elliptic_curve::pkcs8::der::Decodable as Pkcs8Decodable;
@ -81,11 +82,13 @@ pub enum ImportKeyResult {
#[serde(rename_all = "camelCase")]
Ec { raw_data: RawKeyData },
#[serde(rename_all = "camelCase")]
#[allow(dead_code)]
Aes { raw_data: RawKeyData },
#[serde(rename_all = "camelCase")]
Hmac { raw_data: RawKeyData },
}
#[op]
pub fn op_crypto_import_key(
_state: &mut OpState,
opts: ImportKeyOptions,

View file

@ -9,8 +9,8 @@ use deno_core::error::not_supported;
use deno_core::error::type_error;
use deno_core::error::AnyError;
use deno_core::include_js_files;
use deno_core::op_async;
use deno_core::op_sync;
use deno_core::op;
use deno_core::Extension;
use deno_core::OpState;
use deno_core::ZeroCopyBuf;
@ -88,22 +88,19 @@ pub fn init(maybe_seed: Option<u64>) -> Extension {
"01_webidl.js",
))
.ops(vec![
(
"op_crypto_get_random_values",
op_sync(op_crypto_get_random_values),
),
("op_crypto_generate_key", op_async(op_crypto_generate_key)),
("op_crypto_sign_key", op_async(op_crypto_sign_key)),
("op_crypto_verify_key", op_async(op_crypto_verify_key)),
("op_crypto_derive_bits", op_async(op_crypto_derive_bits)),
("op_crypto_import_key", op_sync(op_crypto_import_key)),
("op_crypto_export_key", op_sync(op_crypto_export_key)),
("op_crypto_encrypt", op_async(op_crypto_encrypt)),
("op_crypto_decrypt", op_async(op_crypto_decrypt)),
("op_crypto_subtle_digest", op_async(op_crypto_subtle_digest)),
("op_crypto_random_uuid", op_sync(op_crypto_random_uuid)),
("op_crypto_wrap_key", op_sync(op_crypto_wrap_key)),
("op_crypto_unwrap_key", op_sync(op_crypto_unwrap_key)),
op_crypto_get_random_values::decl(),
op_crypto_generate_key::decl(),
op_crypto_sign_key::decl(),
op_crypto_verify_key::decl(),
op_crypto_derive_bits::decl(),
op_crypto_import_key::decl(),
op_crypto_export_key::decl(),
op_crypto_encrypt::decl(),
op_crypto_decrypt::decl(),
op_crypto_subtle_digest::decl(),
op_crypto_random_uuid::decl(),
op_crypto_wrap_key::decl(),
op_crypto_unwrap_key::decl(),
])
.state(move |state| {
if let Some(seed) = maybe_seed {
@ -114,6 +111,7 @@ pub fn init(maybe_seed: Option<u64>) -> Extension {
.build()
}
#[op]
pub fn op_crypto_get_random_values(
state: &mut OpState,
mut zero_copy: ZeroCopyBuf,
@ -170,6 +168,7 @@ pub struct SignArg {
named_curve: Option<CryptoNamedCurve>,
}
#[op]
pub async fn op_crypto_sign_key(
_state: Rc<RefCell<OpState>>,
args: SignArg,
@ -324,6 +323,7 @@ pub struct VerifyArg {
named_curve: Option<CryptoNamedCurve>,
}
#[op]
pub async fn op_crypto_verify_key(
_state: Rc<RefCell<OpState>>,
args: VerifyArg,
@ -484,6 +484,7 @@ pub struct DeriveKeyArg {
info: Option<ZeroCopyBuf>,
}
#[op]
pub async fn op_crypto_derive_bits(
_state: Rc<RefCell<OpState>>,
args: DeriveKeyArg,
@ -789,6 +790,7 @@ impl<'a> TryFrom<rsa::pkcs8::der::asn1::Any<'a>>
}
}
#[op]
pub fn op_crypto_random_uuid(
state: &mut OpState,
_: (),
@ -808,6 +810,7 @@ pub fn op_crypto_random_uuid(
Ok(uuid.to_string())
}
#[op]
pub async fn op_crypto_subtle_digest(
_state: Rc<RefCell<OpState>>,
algorithm: CryptoHash,
@ -831,6 +834,7 @@ pub struct WrapUnwrapKeyArg {
algorithm: Algorithm,
}
#[op]
pub fn op_crypto_wrap_key(
_state: &mut OpState,
args: WrapUnwrapKeyArg,
@ -860,6 +864,7 @@ pub fn op_crypto_wrap_key(
}
}
#[op]
pub fn op_crypto_unwrap_key(
_state: &mut OpState,
args: WrapUnwrapKeyArg,

View file

@ -9,8 +9,8 @@ use deno_core::futures::Future;
use deno_core::futures::Stream;
use deno_core::futures::StreamExt;
use deno_core::include_js_files;
use deno_core::op_async;
use deno_core::op_sync;
use deno_core::op;
use deno_core::url::Url;
use deno_core::AsyncRefCell;
use deno_core::AsyncResult;
@ -100,12 +100,9 @@ where
"26_fetch.js",
))
.ops(vec![
("op_fetch", op_sync(op_fetch::<FP>)),
("op_fetch_send", op_async(op_fetch_send)),
(
"op_fetch_custom_client",
op_sync(op_fetch_custom_client::<FP>),
),
op_fetch::decl::<FP>(),
op_fetch_send::decl(),
op_fetch_custom_client::decl::<FP>(),
])
.state(move |state| {
state.put::<Options>(options.clone());
@ -192,6 +189,7 @@ pub struct FetchReturn {
cancel_handle_rid: Option<ResourceId>,
}
#[op]
pub fn op_fetch<FP>(
state: &mut OpState,
args: FetchArgs,
@ -367,6 +365,7 @@ pub struct FetchResponse {
response_rid: ResourceId,
}
#[op]
pub async fn op_fetch_send(
state: Rc<RefCell<OpState>>,
rid: ResourceId,
@ -525,6 +524,7 @@ pub struct CreateHttpClientOptions {
private_key: Option<String>,
}
#[op]
pub fn op_fetch_custom_client<FP>(
state: &mut OpState,
args: CreateHttpClientOptions,

View file

@ -6,8 +6,8 @@ use deno_core::error::range_error;
use deno_core::error::type_error;
use deno_core::error::AnyError;
use deno_core::include_js_files;
use deno_core::op_async;
use deno_core::op_sync;
use deno_core::op;
use deno_core::serde_json;
use deno_core::serde_json::json;
use deno_core::serde_json::Value;
@ -140,27 +140,24 @@ pub fn init<P: FfiPermissions + 'static>(unstable: bool) -> Extension {
"00_ffi.js",
))
.ops(vec![
("op_ffi_load", op_sync(op_ffi_load::<P>)),
("op_ffi_get_static", op_sync(op_ffi_get_static)),
("op_ffi_call", op_sync(op_ffi_call)),
("op_ffi_call_nonblocking", op_async(op_ffi_call_nonblocking)),
("op_ffi_call_ptr", op_sync(op_ffi_call_ptr)),
(
"op_ffi_call_ptr_nonblocking",
op_async(op_ffi_call_ptr_nonblocking),
),
("op_ffi_ptr_of", op_sync(op_ffi_ptr_of::<P>)),
("op_ffi_buf_copy_into", op_sync(op_ffi_buf_copy_into::<P>)),
("op_ffi_cstr_read", op_sync(op_ffi_cstr_read::<P>)),
("op_ffi_read_u8", op_sync(op_ffi_read_u8::<P>)),
("op_ffi_read_i8", op_sync(op_ffi_read_i8::<P>)),
("op_ffi_read_u16", op_sync(op_ffi_read_u16::<P>)),
("op_ffi_read_i16", op_sync(op_ffi_read_i16::<P>)),
("op_ffi_read_u32", op_sync(op_ffi_read_u32::<P>)),
("op_ffi_read_i32", op_sync(op_ffi_read_i32::<P>)),
("op_ffi_read_u64", op_sync(op_ffi_read_u64::<P>)),
("op_ffi_read_f32", op_sync(op_ffi_read_f32::<P>)),
("op_ffi_read_f64", op_sync(op_ffi_read_f64::<P>)),
op_ffi_load::decl::<P>(),
op_ffi_get_static::decl(),
op_ffi_call::decl(),
op_ffi_call_nonblocking::decl(),
op_ffi_call_ptr::decl(),
op_ffi_call_ptr_nonblocking::decl(),
op_ffi_ptr_of::decl::<P>(),
op_ffi_buf_copy_into::decl::<P>(),
op_ffi_cstr_read::decl::<P>(),
op_ffi_read_u8::decl::<P>(),
op_ffi_read_i8::decl::<P>(),
op_ffi_read_u16::decl::<P>(),
op_ffi_read_i16::decl::<P>(),
op_ffi_read_u32::decl::<P>(),
op_ffi_read_i32::decl::<P>(),
op_ffi_read_u64::decl::<P>(),
op_ffi_read_f32::decl::<P>(),
op_ffi_read_f64::decl::<P>(),
])
.state(move |state| {
// Stolen from deno_webgpu, is there a better option?
@ -464,6 +461,7 @@ pub(crate) fn format_error(e: dlopen::Error, path: String) -> String {
}
}
#[op]
fn op_ffi_load<FP>(
state: &mut deno_core::OpState,
args: FfiLoadArgs,
@ -650,6 +648,7 @@ fn ffi_call(args: FfiCallArgs, symbol: &Symbol) -> Result<Value, AnyError> {
})
}
#[op]
fn op_ffi_call_ptr(
_state: &mut deno_core::OpState,
args: FfiCallPtrArgs,
@ -659,6 +658,7 @@ fn op_ffi_call_ptr(
ffi_call(args.into(), &symbol)
}
#[op]
async fn op_ffi_call_ptr_nonblocking(
_state: Rc<RefCell<deno_core::OpState>>,
args: FfiCallPtrArgs,
@ -678,6 +678,7 @@ struct FfiGetArgs {
r#type: NativeType,
}
#[op]
fn op_ffi_get_static(
state: &mut deno_core::OpState,
args: FfiGetArgs,
@ -735,6 +736,7 @@ fn op_ffi_get_static(
})
}
#[op]
fn op_ffi_call(
state: &mut deno_core::OpState,
args: FfiCallArgs,
@ -753,6 +755,7 @@ fn op_ffi_call(
}
/// A non-blocking FFI call.
#[op]
async fn op_ffi_call_nonblocking(
state: Rc<RefCell<deno_core::OpState>>,
args: FfiCallArgs,
@ -773,6 +776,7 @@ async fn op_ffi_call_nonblocking(
.unwrap()
}
#[op]
fn op_ffi_ptr_of<FP>(
state: &mut deno_core::OpState,
buf: ZeroCopyBuf,
@ -787,6 +791,7 @@ where
Ok(U32x2::from(buf.as_ptr() as u64))
}
#[op]
fn op_ffi_buf_copy_into<FP>(
state: &mut deno_core::OpState,
(src, mut dst, len): (U32x2, ZeroCopyBuf, usize),
@ -809,6 +814,7 @@ where
}
}
#[op]
fn op_ffi_cstr_read<FP>(
state: &mut deno_core::OpState,
ptr: U32x2,
@ -824,6 +830,7 @@ where
Ok(unsafe { CStr::from_ptr(ptr) }.to_str()?.to_string())
}
#[op]
fn op_ffi_read_u8<FP>(
state: &mut deno_core::OpState,
ptr: U32x2,
@ -838,6 +845,7 @@ where
Ok(unsafe { ptr::read_unaligned(u64::from(ptr) as *const u8) })
}
#[op]
fn op_ffi_read_i8<FP>(
state: &mut deno_core::OpState,
ptr: U32x2,
@ -852,6 +860,7 @@ where
Ok(unsafe { ptr::read_unaligned(u64::from(ptr) as *const i8) })
}
#[op]
fn op_ffi_read_u16<FP>(
state: &mut deno_core::OpState,
ptr: U32x2,
@ -866,6 +875,7 @@ where
Ok(unsafe { ptr::read_unaligned(u64::from(ptr) as *const u16) })
}
#[op]
fn op_ffi_read_i16<FP>(
state: &mut deno_core::OpState,
ptr: U32x2,
@ -880,6 +890,7 @@ where
Ok(unsafe { ptr::read_unaligned(u64::from(ptr) as *const i16) })
}
#[op]
fn op_ffi_read_u32<FP>(
state: &mut deno_core::OpState,
ptr: U32x2,
@ -894,6 +905,7 @@ where
Ok(unsafe { ptr::read_unaligned(u64::from(ptr) as *const u32) })
}
#[op]
fn op_ffi_read_i32<FP>(
state: &mut deno_core::OpState,
ptr: U32x2,
@ -908,6 +920,7 @@ where
Ok(unsafe { ptr::read_unaligned(u64::from(ptr) as *const i32) })
}
#[op]
fn op_ffi_read_u64<FP>(
state: &mut deno_core::OpState,
ptr: U32x2,
@ -924,6 +937,7 @@ where
}))
}
#[op]
fn op_ffi_read_f32<FP>(
state: &mut deno_core::OpState,
ptr: U32x2,
@ -938,6 +952,7 @@ where
Ok(unsafe { ptr::read_unaligned(u64::from(ptr) as *const f32) })
}
#[op]
fn op_ffi_read_f64<FP>(
state: &mut deno_core::OpState,
ptr: U32x2,

View file

@ -20,8 +20,8 @@ use deno_core::futures::FutureExt;
use deno_core::futures::StreamExt;
use deno_core::futures::TryFutureExt;
use deno_core::include_js_files;
use deno_core::op_async;
use deno_core::op_sync;
use deno_core::op;
use deno_core::AsyncRefCell;
use deno_core::ByteString;
use deno_core::CancelFuture;
@ -72,19 +72,13 @@ pub fn init() -> Extension {
"01_http.js",
))
.ops(vec![
("op_http_accept", op_async(op_http_accept)),
("op_http_read", op_async(op_http_read)),
("op_http_write_headers", op_async(op_http_write_headers)),
("op_http_write", op_async(op_http_write)),
("op_http_shutdown", op_async(op_http_shutdown)),
(
"op_http_websocket_accept_header",
op_sync(op_http_websocket_accept_header),
),
(
"op_http_upgrade_websocket",
op_async(op_http_upgrade_websocket),
),
op_http_accept::decl(),
op_http_read::decl(),
op_http_write_headers::decl(),
op_http_write::decl(),
op_http_shutdown::decl(),
op_http_websocket_accept_header::decl(),
op_http_upgrade_websocket::decl(),
])
.build()
}
@ -371,6 +365,7 @@ struct NextRequestResponse(
String,
);
#[op]
async fn op_http_accept(
state: Rc<RefCell<OpState>>,
rid: ResourceId,
@ -501,6 +496,7 @@ struct RespondArgs(
Vec<(ByteString, ByteString)>,
);
#[op]
async fn op_http_write_headers(
state: Rc<RefCell<OpState>>,
args: RespondArgs,
@ -697,6 +693,7 @@ async fn op_http_write_headers(
}
}
#[op]
async fn op_http_write(
state: Rc<RefCell<OpState>>,
rid: ResourceId,
@ -737,6 +734,7 @@ async fn op_http_write(
/// Gracefully closes the write half of the HTTP stream. Note that this does not
/// remove the HTTP stream resource from the resource table; it still has to be
/// closed with `Deno.core.close()`.
#[op]
async fn op_http_shutdown(
state: Rc<RefCell<OpState>>,
rid: ResourceId,
@ -751,6 +749,7 @@ async fn op_http_shutdown(
Ok(())
}
#[op]
async fn op_http_read(
state: Rc<RefCell<OpState>>,
rid: ResourceId,
@ -799,6 +798,7 @@ async fn op_http_read(
fut.try_or_cancel(cancel_handle).await
}
#[op]
fn op_http_websocket_accept_header(
_: &mut OpState,
key: String,
@ -811,6 +811,7 @@ fn op_http_websocket_accept_header(
Ok(base64::encode(digest))
}
#[op]
async fn op_http_upgrade_websocket(
state: Rc<RefCell<OpState>>,
rid: ResourceId,

View file

@ -76,9 +76,6 @@ pub fn init<P: NetPermissions + 'static>(
unstable: bool,
unsafely_ignore_certificate_errors: Option<Vec<String>>,
) -> Extension {
let mut ops_to_register = vec![];
ops_to_register.extend(ops::init::<P>());
ops_to_register.extend(ops_tls::init::<P>());
Extension::builder()
.js(include_js_files!(
prefix "deno:ext/net",
@ -86,7 +83,7 @@ pub fn init<P: NetPermissions + 'static>(
"02_tls.js",
"04_net_unstable.js",
))
.ops(ops_to_register)
.ops([&ops::init::<P>()[..], &ops_tls::init::<P>()[..]].concat())
.state(move |state| {
state.put(DefaultTlsOptions {
root_cert_store: root_cert_store.clone(),

View file

@ -9,8 +9,8 @@ use deno_core::error::custom_error;
use deno_core::error::generic_error;
use deno_core::error::type_error;
use deno_core::error::AnyError;
use deno_core::op_async;
use deno_core::op_sync;
use deno_core::op;
use deno_core::AsyncRefCell;
use deno_core::ByteString;
use deno_core::CancelHandle;
@ -52,14 +52,14 @@ use std::path::Path;
pub fn init<P: NetPermissions + 'static>() -> Vec<OpPair> {
vec![
("op_net_accept", op_async(op_net_accept)),
("op_net_connect", op_async(op_net_connect::<P>)),
("op_net_listen", op_sync(op_net_listen::<P>)),
("op_dgram_recv", op_async(op_dgram_recv)),
("op_dgram_send", op_async(op_dgram_send::<P>)),
("op_dns_resolve", op_async(op_dns_resolve::<P>)),
("op_set_nodelay", op_sync(op_set_nodelay::<P>)),
("op_set_keepalive", op_sync(op_set_keepalive::<P>)),
op_net_accept::decl(),
op_net_connect::decl::<P>(),
op_net_listen::decl::<P>(),
op_dgram_recv::decl(),
op_dgram_send::decl::<P>(),
op_dns_resolve::decl::<P>(),
op_set_nodelay::decl::<P>(),
op_set_keepalive::decl::<P>(),
]
}
@ -158,6 +158,7 @@ async fn accept_tcp(
})
}
#[op]
async fn op_net_accept(
state: Rc<RefCell<OpState>>,
args: AcceptArgs,
@ -210,6 +211,7 @@ async fn receive_udp(
})
}
#[op]
async fn op_dgram_recv(
state: Rc<RefCell<OpState>>,
args: ReceiveArgs,
@ -231,6 +233,7 @@ struct SendArgs {
transport_args: ArgsEnum,
}
#[op]
async fn op_dgram_send<NP>(
state: Rc<RefCell<OpState>>,
args: SendArgs,
@ -299,6 +302,7 @@ pub struct ConnectArgs {
transport_args: ArgsEnum,
}
#[op]
pub async fn op_net_connect<NP>(
state: Rc<RefCell<OpState>>,
args: ConnectArgs,
@ -474,6 +478,7 @@ fn listen_udp(
Ok((rid, local_addr))
}
#[op]
fn op_net_listen<NP>(
state: &mut OpState,
args: ListenArgs,
@ -613,6 +618,7 @@ pub struct NameServer {
port: u16,
}
#[op]
pub async fn op_dns_resolve<NP>(
state: Rc<RefCell<OpState>>,
args: ResolveAddrArgs,
@ -681,6 +687,7 @@ where
Ok(results)
}
#[op]
pub fn op_set_nodelay<NP>(
state: &mut OpState,
rid: ResourceId,
@ -692,6 +699,7 @@ pub fn op_set_nodelay<NP>(
resource.set_nodelay(nodelay)
}
#[op]
pub fn op_set_keepalive<NP>(
state: &mut OpState,
rid: ResourceId,
@ -877,7 +885,7 @@ mod tests {
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
async fn tcp_set_no_delay() {
let set_nodelay = Box::new(|state: &mut OpState, rid| {
op_set_nodelay::<TestPermission>(state, rid, true).unwrap();
op_set_nodelay::call::<TestPermission>(state, rid, true).unwrap();
});
let test_fn = Box::new(|socket: SockRef| {
assert!(socket.nodelay().unwrap());
@ -889,7 +897,7 @@ mod tests {
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
async fn tcp_set_keepalive() {
let set_keepalive = Box::new(|state: &mut OpState, rid| {
op_set_keepalive::<TestPermission>(state, rid, true).unwrap();
op_set_keepalive::call::<TestPermission>(state, rid, true).unwrap();
});
let test_fn = Box::new(|socket: SockRef| {
assert!(!socket.nodelay().unwrap());
@ -934,7 +942,7 @@ mod tests {
};
let connect_fut =
op_net_connect::<TestPermission>(conn_state, connect_args, ());
op_net_connect::call::<TestPermission>(conn_state, connect_args, ());
let conn = connect_fut.await.unwrap();
let rid = conn.rid;

View file

@ -25,8 +25,8 @@ use deno_core::futures::task::Poll;
use deno_core::futures::task::RawWaker;
use deno_core::futures::task::RawWakerVTable;
use deno_core::futures::task::Waker;
use deno_core::op_async;
use deno_core::op_sync;
use deno_core::op;
use deno_core::parking_lot::Mutex;
use deno_core::AsyncRefCell;
use deno_core::AsyncResult;
@ -644,11 +644,11 @@ impl Write for ImplementWriteTrait<'_, TcpStream> {
pub fn init<P: NetPermissions + 'static>() -> Vec<OpPair> {
vec![
("op_tls_start", op_async(op_tls_start::<P>)),
("op_tls_connect", op_async(op_tls_connect::<P>)),
("op_tls_listen", op_sync(op_tls_listen::<P>)),
("op_tls_accept", op_async(op_tls_accept)),
("op_tls_handshake", op_async(op_tls_handshake)),
op_tls_start::decl::<P>(),
op_tls_connect::decl::<P>(),
op_tls_listen::decl::<P>(),
op_tls_accept::decl(),
op_tls_handshake::decl(),
]
}
@ -765,6 +765,7 @@ pub struct StartTlsArgs {
alpn_protocols: Option<Vec<String>>,
}
#[op]
pub async fn op_tls_start<NP>(
state: Rc<RefCell<OpState>>,
args: StartTlsArgs,
@ -857,6 +858,7 @@ where
})
}
#[op]
pub async fn op_tls_connect<NP>(
state: Rc<RefCell<OpState>>,
args: ConnectTlsArgs,
@ -1016,6 +1018,7 @@ pub struct ListenTlsArgs {
alpn_protocols: Option<Vec<String>>,
}
#[op]
pub fn op_tls_listen<NP>(
state: &mut OpState,
args: ListenTlsArgs,
@ -1112,6 +1115,7 @@ where
})
}
#[op]
pub async fn op_tls_accept(
state: Rc<RefCell<OpState>>,
rid: ResourceId,
@ -1163,6 +1167,7 @@ pub async fn op_tls_accept(
})
}
#[op]
pub async fn op_tls_handshake(
state: Rc<RefCell<OpState>>,
rid: ResourceId,

View file

@ -7,7 +7,7 @@ use deno_core::error::type_error;
use deno_core::error::uri_error;
use deno_core::error::AnyError;
use deno_core::include_js_files;
use deno_core::op_sync;
use deno_core::op;
use deno_core::url::form_urlencoded;
use deno_core::url::quirks;
use deno_core::url::Url;
@ -26,21 +26,12 @@ pub fn init() -> Extension {
"01_urlpattern.js",
))
.ops(vec![
("op_url_parse", op_sync(op_url_parse)),
("op_url_reparse", op_sync(op_url_reparse)),
(
"op_url_parse_search_params",
op_sync(op_url_parse_search_params),
),
(
"op_url_stringify_search_params",
op_sync(op_url_stringify_search_params),
),
("op_urlpattern_parse", op_sync(op_urlpattern_parse)),
(
"op_urlpattern_process_match_input",
op_sync(op_urlpattern_process_match_input),
),
op_url_parse::decl(),
op_url_reparse::decl(),
op_url_parse_search_params::decl(),
op_url_stringify_search_params::decl(),
op_urlpattern_parse::decl(),
op_urlpattern_process_match_input::decl(),
])
.build()
}
@ -65,6 +56,7 @@ type UrlParts = String;
/// Parse `UrlParseArgs::href` with an optional `UrlParseArgs::base_href`, or an
/// optional part to "set" after parsing. Return `UrlParts`.
#[op]
pub fn op_url_parse(
_state: &mut deno_core::OpState,
href: String,
@ -98,6 +90,7 @@ pub enum UrlSetter {
Username = 9,
}
#[op]
pub fn op_url_reparse(
_state: &mut deno_core::OpState,
href: String,
@ -167,6 +160,7 @@ fn url_result(
)
}
#[op]
pub fn op_url_parse_search_params(
_state: &mut deno_core::OpState,
args: Option<String>,
@ -186,6 +180,7 @@ pub fn op_url_parse_search_params(
Ok(params)
}
#[op]
pub fn op_url_stringify_search_params(
_state: &mut deno_core::OpState,
args: Vec<(String, String)>,

View file

@ -1,11 +1,13 @@
use deno_core::error::type_error;
use deno_core::error::AnyError;
use deno_core::op;
use urlpattern::quirks;
use urlpattern::quirks::MatchInput;
use urlpattern::quirks::StringOrInit;
use urlpattern::quirks::UrlPattern;
#[op]
pub fn op_urlpattern_parse(
_state: &mut deno_core::OpState,
input: StringOrInit,
@ -23,6 +25,7 @@ pub fn op_urlpattern_parse(
Ok(pattern)
}
#[op]
pub fn op_urlpattern_process_match_input(
_state: &mut deno_core::OpState,
input: StringOrInit,

View file

@ -1,5 +1,7 @@
use async_trait::async_trait;
use deno_core::error::type_error;
use deno_core::op;
use deno_core::parking_lot::Mutex;
use deno_core::url::Url;
use deno_core::ZeroCopyBuf;
@ -157,6 +159,7 @@ impl BlobPart for SlicedBlobPart {
}
}
#[op]
pub fn op_blob_create_part(
state: &mut deno_core::OpState,
data: ZeroCopyBuf,
@ -175,6 +178,7 @@ pub struct SliceOptions {
len: usize,
}
#[op]
pub fn op_blob_slice_part(
state: &mut deno_core::OpState,
id: Uuid,
@ -200,6 +204,7 @@ pub fn op_blob_slice_part(
Ok(id)
}
#[op]
pub async fn op_blob_read_part(
state: Rc<RefCell<deno_core::OpState>>,
id: Uuid,
@ -215,6 +220,7 @@ pub async fn op_blob_read_part(
Ok(ZeroCopyBuf::from(buf.to_vec()))
}
#[op]
pub fn op_blob_remove_part(
state: &mut deno_core::OpState,
id: Uuid,
@ -225,6 +231,7 @@ pub fn op_blob_remove_part(
Ok(())
}
#[op]
pub fn op_blob_create_object_url(
state: &mut deno_core::OpState,
media_type: String,
@ -250,6 +257,7 @@ pub fn op_blob_create_object_url(
Ok(url.to_string())
}
#[op]
pub fn op_blob_revoke_object_url(
state: &mut deno_core::OpState,
url: String,
@ -273,6 +281,7 @@ pub struct ReturnBlobPart {
pub size: usize,
}
#[op]
pub fn op_blob_from_object_url(
state: &mut deno_core::OpState,
url: String,

View file

@ -1,6 +1,7 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
use deno_core::error::AnyError;
use deno_core::op;
use deno_core::OpState;
use deno_core::Resource;
use deno_core::ResourceId;
@ -32,6 +33,7 @@ impl Resource for CompressionResource {
}
}
#[op]
pub fn op_compression_new(
state: &mut OpState,
format: String,
@ -53,6 +55,7 @@ pub fn op_compression_new(
Ok(state.resource_table.add(resource))
}
#[op]
pub fn op_compression_write(
state: &mut OpState,
rid: ResourceId,
@ -86,6 +89,7 @@ pub fn op_compression_write(
Ok(out.into())
}
#[op]
pub fn op_compression_finish(
state: &mut OpState,
rid: ResourceId,

View file

@ -9,8 +9,7 @@ use deno_core::error::range_error;
use deno_core::error::type_error;
use deno_core::error::AnyError;
use deno_core::include_js_files;
use deno_core::op_async;
use deno_core::op_sync;
use deno_core::op;
use deno_core::url::Url;
use deno_core::ByteString;
use deno_core::Extension;
@ -83,58 +82,31 @@ pub fn init<P: TimersPermission + 'static>(
"15_performance.js",
))
.ops(vec![
("op_base64_decode", op_sync(op_base64_decode)),
("op_base64_encode", op_sync(op_base64_encode)),
("op_base64_atob", op_sync(op_base64_atob)),
("op_base64_btoa", op_sync(op_base64_btoa)),
(
"op_encoding_normalize_label",
op_sync(op_encoding_normalize_label),
),
("op_encoding_new_decoder", op_sync(op_encoding_new_decoder)),
("op_encoding_decode", op_sync(op_encoding_decode)),
("op_encoding_encode_into", op_sync(op_encoding_encode_into)),
("op_blob_create_part", op_sync(op_blob_create_part)),
("op_blob_slice_part", op_sync(op_blob_slice_part)),
("op_blob_read_part", op_async(op_blob_read_part)),
("op_blob_remove_part", op_sync(op_blob_remove_part)),
(
"op_blob_create_object_url",
op_sync(op_blob_create_object_url),
),
(
"op_blob_revoke_object_url",
op_sync(op_blob_revoke_object_url),
),
("op_blob_from_object_url", op_sync(op_blob_from_object_url)),
(
"op_message_port_create_entangled",
op_sync(op_message_port_create_entangled),
),
(
"op_message_port_post_message",
op_sync(op_message_port_post_message),
),
(
"op_message_port_recv_message",
op_async(op_message_port_recv_message),
),
(
"op_compression_new",
op_sync(compression::op_compression_new),
),
(
"op_compression_write",
op_sync(compression::op_compression_write),
),
(
"op_compression_finish",
op_sync(compression::op_compression_finish),
),
("op_now", op_sync(op_now::<P>)),
("op_timer_handle", op_sync(op_timer_handle)),
("op_sleep", op_async(op_sleep)),
("op_sleep_sync", op_sync(op_sleep_sync::<P>)),
op_base64_decode::decl(),
op_base64_encode::decl(),
op_base64_atob::decl(),
op_base64_btoa::decl(),
op_encoding_normalize_label::decl(),
op_encoding_new_decoder::decl(),
op_encoding_decode::decl(),
op_encoding_encode_into::decl(),
op_blob_create_part::decl(),
op_blob_slice_part::decl(),
op_blob_read_part::decl(),
op_blob_remove_part::decl(),
op_blob_create_object_url::decl(),
op_blob_revoke_object_url::decl(),
op_blob_from_object_url::decl(),
op_message_port_create_entangled::decl(),
op_message_port_post_message::decl(),
op_message_port_recv_message::decl(),
compression::op_compression_new::decl(),
compression::op_compression_write::decl(),
compression::op_compression_finish::decl(),
op_now::decl::<P>(),
op_timer_handle::decl(),
op_sleep::decl(),
op_sleep_sync::decl::<P>(),
])
.state(move |state| {
state.put(blob_store.clone());
@ -147,6 +119,7 @@ pub fn init<P: TimersPermission + 'static>(
.build()
}
#[op]
fn op_base64_decode(
_: &mut OpState,
input: String,
@ -157,6 +130,7 @@ fn op_base64_decode(
Ok(b64_decode(&input)?.into())
}
#[op]
fn op_base64_atob(
_: &mut OpState,
s: ByteString,
@ -210,6 +184,7 @@ fn b64_decode(input: &[u8]) -> Result<Vec<u8>, AnyError> {
Ok(out)
}
#[op]
fn op_base64_encode(
_: &mut OpState,
s: ZeroCopyBuf,
@ -218,6 +193,7 @@ fn op_base64_encode(
Ok(b64_encode(&s))
}
#[op]
fn op_base64_btoa(
_: &mut OpState,
s: ByteString,
@ -240,6 +216,7 @@ struct DecoderOptions {
fatal: bool,
}
#[op]
fn op_encoding_normalize_label(
_state: &mut OpState,
label: String,
@ -255,6 +232,7 @@ fn op_encoding_normalize_label(
Ok(encoding.name().to_lowercase())
}
#[op]
fn op_encoding_new_decoder(
state: &mut OpState,
options: DecoderOptions,
@ -294,6 +272,7 @@ struct DecodeOptions {
stream: bool,
}
#[op]
fn op_encoding_decode(
state: &mut OpState,
data: ZeroCopyBuf,
@ -357,6 +336,7 @@ struct EncodeIntoResult {
written: usize,
}
#[op]
fn op_encoding_encode_into(
_state: &mut OpState,
input: String,

View file

@ -4,6 +4,8 @@ use std::rc::Rc;
use deno_core::error::type_error;
use deno_core::error::AnyError;
use deno_core::op;
use deno_core::ZeroCopyBuf;
use deno_core::{CancelFuture, Resource};
use deno_core::{CancelHandle, OpState};
@ -104,6 +106,7 @@ impl Resource for MessagePortResource {
}
}
#[op]
pub fn op_message_port_create_entangled(
state: &mut OpState,
_: (),
@ -185,6 +188,7 @@ pub struct JsMessageData {
transferables: Vec<JsTransferable>,
}
#[op]
pub fn op_message_port_post_message(
state: &mut OpState,
rid: ResourceId,
@ -203,6 +207,7 @@ pub fn op_message_port_post_message(
resource.port.send(state, data)
}
#[op]
pub async fn op_message_port_recv_message(
state: Rc<RefCell<OpState>>,
rid: ResourceId,

View file

@ -3,6 +3,8 @@
//! This module helps deno implement timers and performance APIs.
use deno_core::error::AnyError;
use deno_core::op;
use deno_core::CancelFuture;
use deno_core::CancelHandle;
use deno_core::OpState;
@ -25,6 +27,7 @@ pub type StartTime = Instant;
// since the start time of the deno runtime.
// If the High precision flag is not set, the
// nanoseconds are rounded on 2ms.
#[op]
pub fn op_now<TP>(
state: &mut OpState,
_argument: (),
@ -64,6 +67,7 @@ impl Resource for TimerHandle {
/// Creates a [`TimerHandle`] resource that can be used to cancel invocations of
/// [`op_sleep`].
#[op]
pub fn op_timer_handle(
state: &mut OpState,
_: (),
@ -77,6 +81,7 @@ pub fn op_timer_handle(
/// Waits asynchronously until either `millis` milliseconds have passed or the
/// [`TimerHandle`] resource given by `rid` has been canceled.
#[op]
pub async fn op_sleep(
state: Rc<RefCell<OpState>>,
millis: u64,
@ -89,6 +94,7 @@ pub async fn op_sleep(
Ok(())
}
#[op]
pub fn op_sleep_sync<TP>(
state: &mut OpState,
millis: u64,

View file

@ -1,6 +1,7 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
use deno_core::error::AnyError;
use deno_core::op;
use deno_core::ResourceId;
use deno_core::{OpState, Resource};
use serde::Deserialize;
@ -177,6 +178,7 @@ pub struct CreateBindGroupLayoutArgs {
entries: Vec<GpuBindGroupLayoutEntry>,
}
#[op]
pub fn op_webgpu_create_bind_group_layout(
state: &mut OpState,
args: CreateBindGroupLayoutArgs,
@ -220,6 +222,7 @@ pub struct CreatePipelineLayoutArgs {
bind_group_layouts: Vec<u32>,
}
#[op]
pub fn op_webgpu_create_pipeline_layout(
state: &mut OpState,
args: CreatePipelineLayoutArgs,
@ -271,6 +274,7 @@ pub struct CreateBindGroupArgs {
entries: Vec<GpuBindGroupEntry>,
}
#[op]
pub fn op_webgpu_create_bind_group(
state: &mut OpState,
args: CreateBindGroupArgs,

View file

@ -3,6 +3,8 @@
use deno_core::error::type_error;
use deno_core::error::AnyError;
use deno_core::futures::channel::oneshot;
use deno_core::op;
use deno_core::OpState;
use deno_core::Resource;
use deno_core::ResourceId;
@ -40,6 +42,7 @@ pub struct CreateBufferArgs {
mapped_at_creation: bool,
}
#[op]
pub fn op_webgpu_create_buffer(
state: &mut OpState,
args: CreateBufferArgs,
@ -76,6 +79,7 @@ pub struct BufferGetMapAsyncArgs {
size: u64,
}
#[op]
pub async fn op_webgpu_buffer_get_map_async(
state: Rc<RefCell<OpState>>,
args: BufferGetMapAsyncArgs,
@ -167,6 +171,7 @@ pub struct BufferGetMappedRangeArgs {
size: Option<u64>,
}
#[op]
pub fn op_webgpu_buffer_get_mapped_range(
state: &mut OpState,
args: BufferGetMappedRangeArgs,
@ -204,6 +209,7 @@ pub struct BufferUnmapArgs {
mapped_rid: ResourceId,
}
#[op]
pub fn op_webgpu_buffer_unmap(
state: &mut OpState,
args: BufferUnmapArgs,

View file

@ -1,6 +1,7 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
use deno_core::error::AnyError;
use deno_core::op;
use deno_core::ResourceId;
use deno_core::ZeroCopyBuf;
use deno_core::{OpState, Resource};
@ -39,6 +40,7 @@ pub struct CreateRenderBundleEncoderArgs {
stencil_read_only: bool,
}
#[op]
pub fn op_webgpu_create_render_bundle_encoder(
state: &mut OpState,
args: CreateRenderBundleEncoderArgs,
@ -99,6 +101,7 @@ pub struct RenderBundleEncoderFinishArgs {
label: Option<String>,
}
#[op]
pub fn op_webgpu_render_bundle_encoder_finish(
state: &mut OpState,
args: RenderBundleEncoderFinishArgs,
@ -135,6 +138,7 @@ pub struct RenderBundleEncoderSetBindGroupArgs {
dynamic_offsets_data_length: usize,
}
#[op]
pub fn op_webgpu_render_bundle_encoder_set_bind_group(
state: &mut OpState,
args: RenderBundleEncoderSetBindGroupArgs,
@ -189,6 +193,7 @@ pub struct RenderBundleEncoderPushDebugGroupArgs {
group_label: String,
}
#[op]
pub fn op_webgpu_render_bundle_encoder_push_debug_group(
state: &mut OpState,
args: RenderBundleEncoderPushDebugGroupArgs,
@ -218,6 +223,7 @@ pub struct RenderBundleEncoderPopDebugGroupArgs {
render_bundle_encoder_rid: ResourceId,
}
#[op]
pub fn op_webgpu_render_bundle_encoder_pop_debug_group(
state: &mut OpState,
args: RenderBundleEncoderPopDebugGroupArgs,
@ -242,6 +248,7 @@ pub struct RenderBundleEncoderInsertDebugMarkerArgs {
marker_label: String,
}
#[op]
pub fn op_webgpu_render_bundle_encoder_insert_debug_marker(
state: &mut OpState,
args: RenderBundleEncoderInsertDebugMarkerArgs,
@ -272,6 +279,7 @@ pub struct RenderBundleEncoderSetPipelineArgs {
pipeline: ResourceId,
}
#[op]
pub fn op_webgpu_render_bundle_encoder_set_pipeline(
state: &mut OpState,
args: RenderBundleEncoderSetPipelineArgs,
@ -304,6 +312,7 @@ pub struct RenderBundleEncoderSetIndexBufferArgs {
size: u64,
}
#[op]
pub fn op_webgpu_render_bundle_encoder_set_index_buffer(
state: &mut OpState,
args: RenderBundleEncoderSetIndexBufferArgs,
@ -340,6 +349,7 @@ pub struct RenderBundleEncoderSetVertexBufferArgs {
size: u64,
}
#[op]
pub fn op_webgpu_render_bundle_encoder_set_vertex_buffer(
state: &mut OpState,
args: RenderBundleEncoderSetVertexBufferArgs,
@ -374,6 +384,7 @@ pub struct RenderBundleEncoderDrawArgs {
first_instance: u32,
}
#[op]
pub fn op_webgpu_render_bundle_encoder_draw(
state: &mut OpState,
args: RenderBundleEncoderDrawArgs,
@ -406,6 +417,7 @@ pub struct RenderBundleEncoderDrawIndexedArgs {
first_instance: u32,
}
#[op]
pub fn op_webgpu_render_bundle_encoder_draw_indexed(
state: &mut OpState,
args: RenderBundleEncoderDrawIndexedArgs,
@ -436,6 +448,7 @@ pub struct RenderBundleEncoderDrawIndirectArgs {
indirect_offset: u64,
}
#[op]
pub fn op_webgpu_render_bundle_encoder_draw_indirect(
state: &mut OpState,
args: RenderBundleEncoderDrawIndirectArgs,

View file

@ -1,6 +1,7 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
use deno_core::error::AnyError;
use deno_core::op;
use deno_core::ResourceId;
use deno_core::{OpState, Resource};
use serde::Deserialize;
@ -36,6 +37,7 @@ pub struct CreateCommandEncoderArgs {
_measure_execution_time: Option<bool>, // not yet implemented
}
#[op]
pub fn op_webgpu_create_command_encoder(
state: &mut OpState,
args: CreateCommandEncoderArgs,
@ -96,6 +98,7 @@ pub struct CommandEncoderBeginRenderPassArgs {
_occlusion_query_set: Option<u32>, // not yet implemented
}
#[op]
pub fn op_webgpu_command_encoder_begin_render_pass(
state: &mut OpState,
args: CommandEncoderBeginRenderPassArgs,
@ -214,6 +217,7 @@ pub struct CommandEncoderBeginComputePassArgs {
label: Option<String>,
}
#[op]
pub fn op_webgpu_command_encoder_begin_compute_pass(
state: &mut OpState,
args: CommandEncoderBeginComputePassArgs,
@ -252,6 +256,7 @@ pub struct CommandEncoderCopyBufferToBufferArgs {
size: u64,
}
#[op]
pub fn op_webgpu_command_encoder_copy_buffer_to_buffer(
state: &mut OpState,
args: CommandEncoderCopyBufferToBufferArgs,
@ -310,6 +315,7 @@ pub struct CommandEncoderCopyBufferToTextureArgs {
copy_size: wgpu_types::Extent3d,
}
#[op]
pub fn op_webgpu_command_encoder_copy_buffer_to_texture(
state: &mut OpState,
args: CommandEncoderCopyBufferToTextureArgs,
@ -360,6 +366,7 @@ pub struct CommandEncoderCopyTextureToBufferArgs {
copy_size: wgpu_types::Extent3d,
}
#[op]
pub fn op_webgpu_command_encoder_copy_texture_to_buffer(
state: &mut OpState,
args: CommandEncoderCopyTextureToBufferArgs,
@ -414,6 +421,7 @@ pub struct CommandEncoderCopyTextureToTextureArgs {
copy_size: wgpu_types::Extent3d,
}
#[op]
pub fn op_webgpu_command_encoder_copy_texture_to_texture(
state: &mut OpState,
args: CommandEncoderCopyTextureToTextureArgs,
@ -462,6 +470,7 @@ pub struct CommandEncoderClearBufferArgs {
size: u64,
}
#[op]
pub fn op_webgpu_command_encoder_clear_buffer(
state: &mut OpState,
args: CommandEncoderClearBufferArgs,
@ -491,6 +500,7 @@ pub struct CommandEncoderPushDebugGroupArgs {
group_label: String,
}
#[op]
pub fn op_webgpu_command_encoder_push_debug_group(
state: &mut OpState,
args: CommandEncoderPushDebugGroupArgs,
@ -512,6 +522,7 @@ pub struct CommandEncoderPopDebugGroupArgs {
command_encoder_rid: ResourceId,
}
#[op]
pub fn op_webgpu_command_encoder_pop_debug_group(
state: &mut OpState,
args: CommandEncoderPopDebugGroupArgs,
@ -533,6 +544,7 @@ pub struct CommandEncoderInsertDebugMarkerArgs {
marker_label: String,
}
#[op]
pub fn op_webgpu_command_encoder_insert_debug_marker(
state: &mut OpState,
args: CommandEncoderInsertDebugMarkerArgs,
@ -558,6 +570,7 @@ pub struct CommandEncoderWriteTimestampArgs {
query_index: u32,
}
#[op]
pub fn op_webgpu_command_encoder_write_timestamp(
state: &mut OpState,
args: CommandEncoderWriteTimestampArgs,
@ -590,6 +603,7 @@ pub struct CommandEncoderResolveQuerySetArgs {
destination_offset: u64,
}
#[op]
pub fn op_webgpu_command_encoder_resolve_query_set(
state: &mut OpState,
args: CommandEncoderResolveQuerySetArgs,
@ -624,6 +638,7 @@ pub struct CommandEncoderFinishArgs {
label: Option<String>,
}
#[op]
pub fn op_webgpu_command_encoder_finish(
state: &mut OpState,
args: CommandEncoderFinishArgs,

View file

@ -1,6 +1,7 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
use deno_core::error::AnyError;
use deno_core::op;
use deno_core::ResourceId;
use deno_core::ZeroCopyBuf;
use deno_core::{OpState, Resource};
@ -26,6 +27,7 @@ pub struct ComputePassSetPipelineArgs {
pipeline: ResourceId,
}
#[op]
pub fn op_webgpu_compute_pass_set_pipeline(
state: &mut OpState,
args: ComputePassSetPipelineArgs,
@ -56,6 +58,7 @@ pub struct ComputePassDispatchArgs {
z: u32,
}
#[op]
pub fn op_webgpu_compute_pass_dispatch(
state: &mut OpState,
args: ComputePassDispatchArgs,
@ -83,6 +86,7 @@ pub struct ComputePassDispatchIndirectArgs {
indirect_offset: u64,
}
#[op]
pub fn op_webgpu_compute_pass_dispatch_indirect(
state: &mut OpState,
args: ComputePassDispatchIndirectArgs,
@ -112,6 +116,7 @@ pub struct ComputePassBeginPipelineStatisticsQueryArgs {
query_index: u32,
}
#[op]
pub fn op_webgpu_compute_pass_begin_pipeline_statistics_query(
state: &mut OpState,
args: ComputePassBeginPipelineStatisticsQueryArgs,
@ -139,6 +144,7 @@ pub struct ComputePassEndPipelineStatisticsQueryArgs {
compute_pass_rid: ResourceId,
}
#[op]
pub fn op_webgpu_compute_pass_end_pipeline_statistics_query(
state: &mut OpState,
args: ComputePassEndPipelineStatisticsQueryArgs,
@ -163,6 +169,7 @@ pub struct ComputePassWriteTimestampArgs {
query_index: u32,
}
#[op]
pub fn op_webgpu_compute_pass_write_timestamp(
state: &mut OpState,
args: ComputePassWriteTimestampArgs,
@ -191,6 +198,7 @@ pub struct ComputePassEndPassArgs {
compute_pass_rid: ResourceId,
}
#[op]
pub fn op_webgpu_compute_pass_end_pass(
state: &mut OpState,
args: ComputePassEndPassArgs,
@ -225,6 +233,7 @@ pub struct ComputePassSetBindGroupArgs {
dynamic_offsets_data_length: usize,
}
#[op]
pub fn op_webgpu_compute_pass_set_bind_group(
state: &mut OpState,
args: ComputePassSetBindGroupArgs,
@ -278,6 +287,7 @@ pub struct ComputePassPushDebugGroupArgs {
group_label: String,
}
#[op]
pub fn op_webgpu_compute_pass_push_debug_group(
state: &mut OpState,
args: ComputePassPushDebugGroupArgs,
@ -307,6 +317,7 @@ pub struct ComputePassPopDebugGroupArgs {
compute_pass_rid: ResourceId,
}
#[op]
pub fn op_webgpu_compute_pass_pop_debug_group(
state: &mut OpState,
args: ComputePassPopDebugGroupArgs,
@ -330,6 +341,7 @@ pub struct ComputePassInsertDebugMarkerArgs {
marker_label: String,
}
#[op]
pub fn op_webgpu_compute_pass_insert_debug_marker(
state: &mut OpState,
args: ComputePassInsertDebugMarkerArgs,

View file

@ -2,10 +2,10 @@
use deno_core::error::AnyError;
use deno_core::include_js_files;
use deno_core::op_async;
use deno_core::op_sync;
use deno_core::op;
use deno_core::Extension;
use deno_core::OpFn;
use deno_core::OpPair;
use deno_core::OpState;
use deno_core::Resource;
use deno_core::ResourceId;
@ -241,6 +241,7 @@ pub struct GpuAdapterDevice {
is_software: bool,
}
#[op]
pub async fn op_webgpu_request_adapter(
state: Rc<RefCell<OpState>>,
args: RequestAdapterArgs,
@ -439,6 +440,7 @@ impl From<GpuRequiredFeatures> for wgpu_types::Features {
}
}
#[op]
pub async fn op_webgpu_request_device(
state: Rc<RefCell<OpState>>,
args: RequestDeviceArgs,
@ -539,6 +541,7 @@ impl From<GpuQueryType> for wgpu_types::QueryType {
}
}
#[op]
pub fn op_webgpu_create_query_set(
state: &mut OpState,
args: CreateQuerySetArgs,
@ -562,347 +565,102 @@ pub fn op_webgpu_create_query_set(
) => state, WebGpuQuerySet)
}
fn declare_webgpu_ops() -> Vec<(&'static str, Box<OpFn>)> {
fn declare_webgpu_ops() -> Vec<OpPair> {
vec![
// Request device/adapter
(
"op_webgpu_request_adapter",
op_async(op_webgpu_request_adapter),
),
(
"op_webgpu_request_device",
op_async(op_webgpu_request_device),
),
op_webgpu_request_adapter::decl(),
op_webgpu_request_device::decl(),
// Query Set
(
"op_webgpu_create_query_set",
op_sync(op_webgpu_create_query_set),
),
op_webgpu_create_query_set::decl(),
// buffer
(
"op_webgpu_create_buffer",
op_sync(buffer::op_webgpu_create_buffer),
),
(
"op_webgpu_buffer_get_mapped_range",
op_sync(buffer::op_webgpu_buffer_get_mapped_range),
),
(
"op_webgpu_buffer_unmap",
op_sync(buffer::op_webgpu_buffer_unmap),
),
buffer::op_webgpu_create_buffer::decl(),
buffer::op_webgpu_buffer_get_mapped_range::decl(),
buffer::op_webgpu_buffer_unmap::decl(),
// buffer async
(
"op_webgpu_buffer_get_map_async",
op_async(buffer::op_webgpu_buffer_get_map_async),
),
buffer::op_webgpu_buffer_get_map_async::decl(),
// remaining sync ops
// texture
(
"op_webgpu_create_texture",
op_sync(texture::op_webgpu_create_texture),
),
(
"op_webgpu_create_texture_view",
op_sync(texture::op_webgpu_create_texture_view),
),
texture::op_webgpu_create_texture::decl(),
texture::op_webgpu_create_texture_view::decl(),
// sampler
(
"op_webgpu_create_sampler",
op_sync(sampler::op_webgpu_create_sampler),
),
sampler::op_webgpu_create_sampler::decl(),
// binding
(
"op_webgpu_create_bind_group_layout",
op_sync(binding::op_webgpu_create_bind_group_layout),
),
(
"op_webgpu_create_pipeline_layout",
op_sync(binding::op_webgpu_create_pipeline_layout),
),
(
"op_webgpu_create_bind_group",
op_sync(binding::op_webgpu_create_bind_group),
),
binding::op_webgpu_create_bind_group_layout::decl(),
binding::op_webgpu_create_pipeline_layout::decl(),
binding::op_webgpu_create_bind_group::decl(),
// pipeline
(
"op_webgpu_create_compute_pipeline",
op_sync(pipeline::op_webgpu_create_compute_pipeline),
),
(
"op_webgpu_compute_pipeline_get_bind_group_layout",
op_sync(pipeline::op_webgpu_compute_pipeline_get_bind_group_layout),
),
(
"op_webgpu_create_render_pipeline",
op_sync(pipeline::op_webgpu_create_render_pipeline),
),
(
"op_webgpu_render_pipeline_get_bind_group_layout",
op_sync(pipeline::op_webgpu_render_pipeline_get_bind_group_layout),
),
pipeline::op_webgpu_create_compute_pipeline::decl(),
pipeline::op_webgpu_compute_pipeline_get_bind_group_layout::decl(),
pipeline::op_webgpu_create_render_pipeline::decl(),
pipeline::op_webgpu_render_pipeline_get_bind_group_layout::decl(),
// command_encoder
(
"op_webgpu_create_command_encoder",
op_sync(command_encoder::op_webgpu_create_command_encoder),
),
(
"op_webgpu_command_encoder_begin_render_pass",
op_sync(command_encoder::op_webgpu_command_encoder_begin_render_pass),
),
(
"op_webgpu_command_encoder_begin_compute_pass",
op_sync(command_encoder::op_webgpu_command_encoder_begin_compute_pass),
),
(
"op_webgpu_command_encoder_copy_buffer_to_buffer",
op_sync(command_encoder::op_webgpu_command_encoder_copy_buffer_to_buffer),
),
(
"op_webgpu_command_encoder_copy_buffer_to_texture",
op_sync(
command_encoder::op_webgpu_command_encoder_copy_buffer_to_texture,
),
),
(
"op_webgpu_command_encoder_copy_texture_to_buffer",
op_sync(
command_encoder::op_webgpu_command_encoder_copy_texture_to_buffer,
),
),
(
"op_webgpu_command_encoder_copy_texture_to_texture",
op_sync(
command_encoder::op_webgpu_command_encoder_copy_texture_to_texture,
),
),
(
"op_webgpu_command_encoder_clear_buffer",
op_sync(command_encoder::op_webgpu_command_encoder_clear_buffer),
),
(
"op_webgpu_command_encoder_push_debug_group",
op_sync(command_encoder::op_webgpu_command_encoder_push_debug_group),
),
(
"op_webgpu_command_encoder_pop_debug_group",
op_sync(command_encoder::op_webgpu_command_encoder_pop_debug_group),
),
(
"op_webgpu_command_encoder_insert_debug_marker",
op_sync(command_encoder::op_webgpu_command_encoder_insert_debug_marker),
),
(
"op_webgpu_command_encoder_write_timestamp",
op_sync(command_encoder::op_webgpu_command_encoder_write_timestamp),
),
(
"op_webgpu_command_encoder_resolve_query_set",
op_sync(command_encoder::op_webgpu_command_encoder_resolve_query_set),
),
(
"op_webgpu_command_encoder_finish",
op_sync(command_encoder::op_webgpu_command_encoder_finish),
),
command_encoder::op_webgpu_create_command_encoder::decl(),
command_encoder::op_webgpu_command_encoder_begin_render_pass::decl(),
command_encoder::op_webgpu_command_encoder_begin_compute_pass::decl(),
command_encoder::op_webgpu_command_encoder_copy_buffer_to_buffer::decl(),
command_encoder::op_webgpu_command_encoder_copy_buffer_to_texture::decl(),
command_encoder::op_webgpu_command_encoder_copy_texture_to_buffer::decl(),
command_encoder::op_webgpu_command_encoder_copy_texture_to_texture::decl(),
command_encoder::op_webgpu_command_encoder_clear_buffer::decl(),
command_encoder::op_webgpu_command_encoder_push_debug_group::decl(),
command_encoder::op_webgpu_command_encoder_pop_debug_group::decl(),
command_encoder::op_webgpu_command_encoder_insert_debug_marker::decl(),
command_encoder::op_webgpu_command_encoder_write_timestamp::decl(),
command_encoder::op_webgpu_command_encoder_resolve_query_set::decl(),
command_encoder::op_webgpu_command_encoder_finish::decl(),
// render_pass
(
"op_webgpu_render_pass_set_viewport",
op_sync(render_pass::op_webgpu_render_pass_set_viewport),
),
(
"op_webgpu_render_pass_set_scissor_rect",
op_sync(render_pass::op_webgpu_render_pass_set_scissor_rect),
),
(
"op_webgpu_render_pass_set_blend_constant",
op_sync(render_pass::op_webgpu_render_pass_set_blend_constant),
),
(
"op_webgpu_render_pass_set_stencil_reference",
op_sync(render_pass::op_webgpu_render_pass_set_stencil_reference),
),
(
"op_webgpu_render_pass_begin_pipeline_statistics_query",
op_sync(
render_pass::op_webgpu_render_pass_begin_pipeline_statistics_query,
),
),
(
"op_webgpu_render_pass_end_pipeline_statistics_query",
op_sync(render_pass::op_webgpu_render_pass_end_pipeline_statistics_query),
),
(
"op_webgpu_render_pass_write_timestamp",
op_sync(render_pass::op_webgpu_render_pass_write_timestamp),
),
(
"op_webgpu_render_pass_execute_bundles",
op_sync(render_pass::op_webgpu_render_pass_execute_bundles),
),
(
"op_webgpu_render_pass_end_pass",
op_sync(render_pass::op_webgpu_render_pass_end_pass),
),
(
"op_webgpu_render_pass_set_bind_group",
op_sync(render_pass::op_webgpu_render_pass_set_bind_group),
),
(
"op_webgpu_render_pass_push_debug_group",
op_sync(render_pass::op_webgpu_render_pass_push_debug_group),
),
(
"op_webgpu_render_pass_pop_debug_group",
op_sync(render_pass::op_webgpu_render_pass_pop_debug_group),
),
(
"op_webgpu_render_pass_insert_debug_marker",
op_sync(render_pass::op_webgpu_render_pass_insert_debug_marker),
),
(
"op_webgpu_render_pass_set_pipeline",
op_sync(render_pass::op_webgpu_render_pass_set_pipeline),
),
(
"op_webgpu_render_pass_set_index_buffer",
op_sync(render_pass::op_webgpu_render_pass_set_index_buffer),
),
(
"op_webgpu_render_pass_set_vertex_buffer",
op_sync(render_pass::op_webgpu_render_pass_set_vertex_buffer),
),
(
"op_webgpu_render_pass_draw",
op_sync(render_pass::op_webgpu_render_pass_draw),
),
(
"op_webgpu_render_pass_draw_indexed",
op_sync(render_pass::op_webgpu_render_pass_draw_indexed),
),
(
"op_webgpu_render_pass_draw_indirect",
op_sync(render_pass::op_webgpu_render_pass_draw_indirect),
),
(
"op_webgpu_render_pass_draw_indexed_indirect",
op_sync(render_pass::op_webgpu_render_pass_draw_indexed_indirect),
),
render_pass::op_webgpu_render_pass_set_viewport::decl(),
render_pass::op_webgpu_render_pass_set_scissor_rect::decl(),
render_pass::op_webgpu_render_pass_set_blend_constant::decl(),
render_pass::op_webgpu_render_pass_set_stencil_reference::decl(),
render_pass::op_webgpu_render_pass_begin_pipeline_statistics_query::decl(),
render_pass::op_webgpu_render_pass_end_pipeline_statistics_query::decl(),
render_pass::op_webgpu_render_pass_write_timestamp::decl(),
render_pass::op_webgpu_render_pass_execute_bundles::decl(),
render_pass::op_webgpu_render_pass_end_pass::decl(),
render_pass::op_webgpu_render_pass_set_bind_group::decl(),
render_pass::op_webgpu_render_pass_push_debug_group::decl(),
render_pass::op_webgpu_render_pass_pop_debug_group::decl(),
render_pass::op_webgpu_render_pass_insert_debug_marker::decl(),
render_pass::op_webgpu_render_pass_set_pipeline::decl(),
render_pass::op_webgpu_render_pass_set_index_buffer::decl(),
render_pass::op_webgpu_render_pass_set_vertex_buffer::decl(),
render_pass::op_webgpu_render_pass_draw::decl(),
render_pass::op_webgpu_render_pass_draw_indexed::decl(),
render_pass::op_webgpu_render_pass_draw_indirect::decl(),
render_pass::op_webgpu_render_pass_draw_indexed_indirect::decl(),
// compute_pass
(
"op_webgpu_compute_pass_set_pipeline",
op_sync(compute_pass::op_webgpu_compute_pass_set_pipeline),
),
(
"op_webgpu_compute_pass_dispatch",
op_sync(compute_pass::op_webgpu_compute_pass_dispatch),
),
(
"op_webgpu_compute_pass_dispatch_indirect",
op_sync(compute_pass::op_webgpu_compute_pass_dispatch_indirect),
),
(
"op_webgpu_compute_pass_begin_pipeline_statistics_query",
op_sync(
compute_pass::op_webgpu_compute_pass_begin_pipeline_statistics_query,
),
),
(
"op_webgpu_compute_pass_end_pipeline_statistics_query",
op_sync(
compute_pass::op_webgpu_compute_pass_end_pipeline_statistics_query,
),
),
(
"op_webgpu_compute_pass_write_timestamp",
op_sync(compute_pass::op_webgpu_compute_pass_write_timestamp),
),
(
"op_webgpu_compute_pass_end_pass",
op_sync(compute_pass::op_webgpu_compute_pass_end_pass),
),
(
"op_webgpu_compute_pass_set_bind_group",
op_sync(compute_pass::op_webgpu_compute_pass_set_bind_group),
),
(
"op_webgpu_compute_pass_push_debug_group",
op_sync(compute_pass::op_webgpu_compute_pass_push_debug_group),
),
(
"op_webgpu_compute_pass_pop_debug_group",
op_sync(compute_pass::op_webgpu_compute_pass_pop_debug_group),
),
(
"op_webgpu_compute_pass_insert_debug_marker",
op_sync(compute_pass::op_webgpu_compute_pass_insert_debug_marker),
compute_pass::op_webgpu_compute_pass_set_pipeline::decl(),
compute_pass::op_webgpu_compute_pass_dispatch::decl(),
compute_pass::op_webgpu_compute_pass_dispatch_indirect::decl(),
compute_pass::op_webgpu_compute_pass_begin_pipeline_statistics_query::decl(
),
compute_pass::op_webgpu_compute_pass_end_pipeline_statistics_query::decl(),
compute_pass::op_webgpu_compute_pass_write_timestamp::decl(),
compute_pass::op_webgpu_compute_pass_end_pass::decl(),
compute_pass::op_webgpu_compute_pass_set_bind_group::decl(),
compute_pass::op_webgpu_compute_pass_push_debug_group::decl(),
compute_pass::op_webgpu_compute_pass_pop_debug_group::decl(),
compute_pass::op_webgpu_compute_pass_insert_debug_marker::decl(),
// bundle
(
"op_webgpu_create_render_bundle_encoder",
op_sync(bundle::op_webgpu_create_render_bundle_encoder),
),
(
"op_webgpu_render_bundle_encoder_finish",
op_sync(bundle::op_webgpu_render_bundle_encoder_finish),
),
(
"op_webgpu_render_bundle_encoder_set_bind_group",
op_sync(bundle::op_webgpu_render_bundle_encoder_set_bind_group),
),
(
"op_webgpu_render_bundle_encoder_push_debug_group",
op_sync(bundle::op_webgpu_render_bundle_encoder_push_debug_group),
),
(
"op_webgpu_render_bundle_encoder_pop_debug_group",
op_sync(bundle::op_webgpu_render_bundle_encoder_pop_debug_group),
),
(
"op_webgpu_render_bundle_encoder_insert_debug_marker",
op_sync(bundle::op_webgpu_render_bundle_encoder_insert_debug_marker),
),
(
"op_webgpu_render_bundle_encoder_set_pipeline",
op_sync(bundle::op_webgpu_render_bundle_encoder_set_pipeline),
),
(
"op_webgpu_render_bundle_encoder_set_index_buffer",
op_sync(bundle::op_webgpu_render_bundle_encoder_set_index_buffer),
),
(
"op_webgpu_render_bundle_encoder_set_vertex_buffer",
op_sync(bundle::op_webgpu_render_bundle_encoder_set_vertex_buffer),
),
(
"op_webgpu_render_bundle_encoder_draw",
op_sync(bundle::op_webgpu_render_bundle_encoder_draw),
),
(
"op_webgpu_render_bundle_encoder_draw_indexed",
op_sync(bundle::op_webgpu_render_bundle_encoder_draw_indexed),
),
(
"op_webgpu_render_bundle_encoder_draw_indirect",
op_sync(bundle::op_webgpu_render_bundle_encoder_draw_indirect),
),
bundle::op_webgpu_create_render_bundle_encoder::decl(),
bundle::op_webgpu_render_bundle_encoder_finish::decl(),
bundle::op_webgpu_render_bundle_encoder_set_bind_group::decl(),
bundle::op_webgpu_render_bundle_encoder_push_debug_group::decl(),
bundle::op_webgpu_render_bundle_encoder_pop_debug_group::decl(),
bundle::op_webgpu_render_bundle_encoder_insert_debug_marker::decl(),
bundle::op_webgpu_render_bundle_encoder_set_pipeline::decl(),
bundle::op_webgpu_render_bundle_encoder_set_index_buffer::decl(),
bundle::op_webgpu_render_bundle_encoder_set_vertex_buffer::decl(),
bundle::op_webgpu_render_bundle_encoder_draw::decl(),
bundle::op_webgpu_render_bundle_encoder_draw_indexed::decl(),
bundle::op_webgpu_render_bundle_encoder_draw_indirect::decl(),
// queue
(
"op_webgpu_queue_submit",
op_sync(queue::op_webgpu_queue_submit),
),
(
"op_webgpu_write_buffer",
op_sync(queue::op_webgpu_write_buffer),
),
(
"op_webgpu_write_texture",
op_sync(queue::op_webgpu_write_texture),
),
queue::op_webgpu_queue_submit::decl(),
queue::op_webgpu_write_buffer::decl(),
queue::op_webgpu_write_texture::decl(),
// shader
(
"op_webgpu_create_shader_module",
op_sync(shader::op_webgpu_create_shader_module),
),
shader::op_webgpu_create_shader_module::decl(),
]
}

View file

@ -1,6 +1,7 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
use deno_core::error::AnyError;
use deno_core::op;
use deno_core::ResourceId;
use deno_core::{OpState, Resource};
use serde::Deserialize;
@ -57,6 +58,7 @@ pub struct CreateComputePipelineArgs {
compute: GpuProgrammableStage,
}
#[op]
pub fn op_webgpu_create_compute_pipeline(
state: &mut OpState,
args: CreateComputePipelineArgs,
@ -126,6 +128,7 @@ pub struct PipelineLayout {
err: Option<WebGpuError>,
}
#[op]
pub fn op_webgpu_compute_pipeline_get_bind_group_layout(
state: &mut OpState,
args: ComputePipelineGetBindGroupLayoutArgs,
@ -303,6 +306,7 @@ pub struct CreateRenderPipelineArgs {
fragment: Option<GpuFragmentState>,
}
#[op]
pub fn op_webgpu_create_render_pipeline(
state: &mut OpState,
args: CreateRenderPipelineArgs,
@ -404,6 +408,7 @@ pub struct RenderPipelineGetBindGroupLayoutArgs {
index: u32,
}
#[op]
pub fn op_webgpu_render_pipeline_get_bind_group_layout(
state: &mut OpState,
args: RenderPipelineGetBindGroupLayoutArgs,

View file

@ -3,6 +3,7 @@
use std::num::NonZeroU32;
use deno_core::error::AnyError;
use deno_core::op;
use deno_core::OpState;
use deno_core::ResourceId;
use deno_core::ZeroCopyBuf;
@ -19,6 +20,7 @@ pub struct QueueSubmitArgs {
command_buffers: Vec<ResourceId>,
}
#[op]
pub fn op_webgpu_queue_submit(
state: &mut OpState,
args: QueueSubmitArgs,
@ -73,6 +75,7 @@ pub struct QueueWriteBufferArgs {
size: Option<usize>,
}
#[op]
pub fn op_webgpu_write_buffer(
state: &mut OpState,
args: QueueWriteBufferArgs,
@ -111,6 +114,7 @@ pub struct QueueWriteTextureArgs {
size: wgpu_types::Extent3d,
}
#[op]
pub fn op_webgpu_write_texture(
state: &mut OpState,
args: QueueWriteTextureArgs,

View file

@ -2,6 +2,7 @@
use deno_core::error::type_error;
use deno_core::error::AnyError;
use deno_core::op;
use deno_core::ResourceId;
use deno_core::ZeroCopyBuf;
use deno_core::{OpState, Resource};
@ -32,6 +33,7 @@ pub struct RenderPassSetViewportArgs {
max_depth: f32,
}
#[op]
pub fn op_webgpu_render_pass_set_viewport(
state: &mut OpState,
args: RenderPassSetViewportArgs,
@ -64,6 +66,7 @@ pub struct RenderPassSetScissorRectArgs {
height: u32,
}
#[op]
pub fn op_webgpu_render_pass_set_scissor_rect(
state: &mut OpState,
args: RenderPassSetScissorRectArgs,
@ -91,6 +94,7 @@ pub struct RenderPassSetBlendConstantArgs {
color: wgpu_types::Color,
}
#[op]
pub fn op_webgpu_render_pass_set_blend_constant(
state: &mut OpState,
args: RenderPassSetBlendConstantArgs,
@ -115,6 +119,7 @@ pub struct RenderPassSetStencilReferenceArgs {
reference: u32,
}
#[op]
pub fn op_webgpu_render_pass_set_stencil_reference(
state: &mut OpState,
args: RenderPassSetStencilReferenceArgs,
@ -140,6 +145,7 @@ pub struct RenderPassBeginPipelineStatisticsQueryArgs {
query_index: u32,
}
#[op]
pub fn op_webgpu_render_pass_begin_pipeline_statistics_query(
state: &mut OpState,
args: RenderPassBeginPipelineStatisticsQueryArgs,
@ -167,6 +173,7 @@ pub struct RenderPassEndPipelineStatisticsQueryArgs {
render_pass_rid: ResourceId,
}
#[op]
pub fn op_webgpu_render_pass_end_pipeline_statistics_query(
state: &mut OpState,
args: RenderPassEndPipelineStatisticsQueryArgs,
@ -191,6 +198,7 @@ pub struct RenderPassWriteTimestampArgs {
query_index: u32,
}
#[op]
pub fn op_webgpu_render_pass_write_timestamp(
state: &mut OpState,
args: RenderPassWriteTimestampArgs,
@ -219,6 +227,7 @@ pub struct RenderPassExecuteBundlesArgs {
bundles: Vec<u32>,
}
#[op]
pub fn op_webgpu_render_pass_execute_bundles(
state: &mut OpState,
args: RenderPassExecuteBundlesArgs,
@ -258,6 +267,7 @@ pub struct RenderPassEndPassArgs {
render_pass_rid: ResourceId,
}
#[op]
pub fn op_webgpu_render_pass_end_pass(
state: &mut OpState,
args: RenderPassEndPassArgs,
@ -289,6 +299,7 @@ pub struct RenderPassSetBindGroupArgs {
dynamic_offsets_data_length: usize,
}
#[op]
pub fn op_webgpu_render_pass_set_bind_group(
state: &mut OpState,
args: RenderPassSetBindGroupArgs,
@ -342,6 +353,7 @@ pub struct RenderPassPushDebugGroupArgs {
group_label: String,
}
#[op]
pub fn op_webgpu_render_pass_push_debug_group(
state: &mut OpState,
args: RenderPassPushDebugGroupArgs,
@ -371,6 +383,7 @@ pub struct RenderPassPopDebugGroupArgs {
render_pass_rid: ResourceId,
}
#[op]
pub fn op_webgpu_render_pass_pop_debug_group(
state: &mut OpState,
args: RenderPassPopDebugGroupArgs,
@ -394,6 +407,7 @@ pub struct RenderPassInsertDebugMarkerArgs {
marker_label: String,
}
#[op]
pub fn op_webgpu_render_pass_insert_debug_marker(
state: &mut OpState,
args: RenderPassInsertDebugMarkerArgs,
@ -424,6 +438,7 @@ pub struct RenderPassSetPipelineArgs {
pipeline: u32,
}
#[op]
pub fn op_webgpu_render_pass_set_pipeline(
state: &mut OpState,
args: RenderPassSetPipelineArgs,
@ -455,6 +470,7 @@ pub struct RenderPassSetIndexBufferArgs {
size: Option<u64>,
}
#[op]
pub fn op_webgpu_render_pass_set_index_buffer(
state: &mut OpState,
args: RenderPassSetIndexBufferArgs,
@ -496,6 +512,7 @@ pub struct RenderPassSetVertexBufferArgs {
size: Option<u64>,
}
#[op]
pub fn op_webgpu_render_pass_set_vertex_buffer(
state: &mut OpState,
args: RenderPassSetVertexBufferArgs,
@ -538,6 +555,7 @@ pub struct RenderPassDrawArgs {
first_instance: u32,
}
#[op]
pub fn op_webgpu_render_pass_draw(
state: &mut OpState,
args: RenderPassDrawArgs,
@ -569,6 +587,7 @@ pub struct RenderPassDrawIndexedArgs {
first_instance: u32,
}
#[op]
pub fn op_webgpu_render_pass_draw_indexed(
state: &mut OpState,
args: RenderPassDrawIndexedArgs,
@ -598,6 +617,7 @@ pub struct RenderPassDrawIndirectArgs {
indirect_offset: u64,
}
#[op]
pub fn op_webgpu_render_pass_draw_indirect(
state: &mut OpState,
args: RenderPassDrawIndirectArgs,
@ -627,6 +647,7 @@ pub struct RenderPassDrawIndexedIndirectArgs {
indirect_offset: u64,
}
#[op]
pub fn op_webgpu_render_pass_draw_indexed_indirect(
state: &mut OpState,
args: RenderPassDrawIndexedIndirectArgs,

View file

@ -1,6 +1,7 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
use deno_core::error::AnyError;
use deno_core::op;
use deno_core::ResourceId;
use deno_core::{OpState, Resource};
use serde::Deserialize;
@ -32,6 +33,7 @@ pub struct CreateSamplerArgs {
max_anisotropy: u8,
}
#[op]
pub fn op_webgpu_create_sampler(
state: &mut OpState,
args: CreateSamplerArgs,

View file

@ -1,6 +1,7 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
use deno_core::error::AnyError;
use deno_core::op;
use deno_core::ResourceId;
use deno_core::{OpState, Resource};
use serde::Deserialize;
@ -24,6 +25,7 @@ pub struct CreateShaderModuleArgs {
_source_map: Option<()>, // not yet implemented
}
#[op]
pub fn op_webgpu_create_shader_module(
state: &mut OpState,
args: CreateShaderModuleArgs,

View file

@ -1,6 +1,7 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
use deno_core::error::AnyError;
use deno_core::op;
use deno_core::ResourceId;
use deno_core::{OpState, Resource};
use serde::Deserialize;
@ -34,6 +35,7 @@ pub struct CreateTextureArgs {
usage: u32,
}
#[op]
pub fn op_webgpu_create_texture(
state: &mut OpState,
args: CreateTextureArgs,
@ -76,6 +78,7 @@ pub struct CreateTextureViewArgs {
array_layer_count: Option<u32>,
}
#[op]
pub fn op_webgpu_create_texture_view(
state: &mut OpState,
args: CreateTextureViewArgs,

View file

@ -8,8 +8,8 @@ use deno_core::futures::stream::SplitStream;
use deno_core::futures::SinkExt;
use deno_core::futures::StreamExt;
use deno_core::include_js_files;
use deno_core::op_async;
use deno_core::op_sync;
use deno_core::op;
use deno_core::url;
use deno_core::AsyncRefCell;
use deno_core::ByteString;
@ -190,6 +190,7 @@ impl Resource for WsCancelResource {
// This op is needed because creating a WS instance in JavaScript is a sync
// operation and should throw error when permissions are not fulfilled,
// but actual op that connects WS is async.
#[op]
pub fn op_ws_check_permission_and_cancel_handle<WP>(
state: &mut OpState,
url: String,
@ -229,6 +230,7 @@ pub struct CreateResponse {
extensions: String,
}
#[op]
pub async fn op_ws_create<WP>(
state: Rc<RefCell<OpState>>,
args: CreateArgs,
@ -378,6 +380,7 @@ pub enum SendValue {
Ping,
}
#[op]
pub async fn op_ws_send(
state: Rc<RefCell<OpState>>,
rid: ResourceId,
@ -406,6 +409,7 @@ pub struct CloseArgs {
reason: Option<String>,
}
#[op]
pub async fn op_ws_close(
state: Rc<RefCell<OpState>>,
args: CloseArgs,
@ -440,6 +444,7 @@ pub enum NextEventResponse {
Closed,
}
#[op]
pub async fn op_ws_next_event(
state: Rc<RefCell<OpState>>,
rid: ResourceId,
@ -486,14 +491,11 @@ pub fn init<P: WebSocketPermissions + 'static>(
"02_websocketstream.js",
))
.ops(vec![
(
"op_ws_check_permission_and_cancel_handle",
op_sync(op_ws_check_permission_and_cancel_handle::<P>),
),
("op_ws_create", op_async(op_ws_create::<P>)),
("op_ws_send", op_async(op_ws_send)),
("op_ws_close", op_async(op_ws_close)),
("op_ws_next_event", op_async(op_ws_next_event)),
op_ws_check_permission_and_cancel_handle::decl::<P>(),
op_ws_create::decl::<P>(),
op_ws_send::decl(),
op_ws_close::decl(),
op_ws_next_event::decl(),
])
.state(move |state| {
state.put::<WsUserAgent>(WsUserAgent(user_agent.clone()));

View file

@ -4,7 +4,7 @@
use deno_core::error::AnyError;
use deno_core::include_js_files;
use deno_core::op_sync;
use deno_core::op;
use deno_core::Extension;
use deno_core::OpState;
use rusqlite::params;
@ -26,16 +26,13 @@ pub fn init(origin_storage_dir: Option<PathBuf>) -> Extension {
"01_webstorage.js",
))
.ops(vec![
("op_webstorage_length", op_sync(op_webstorage_length)),
("op_webstorage_key", op_sync(op_webstorage_key)),
("op_webstorage_set", op_sync(op_webstorage_set)),
("op_webstorage_get", op_sync(op_webstorage_get)),
("op_webstorage_remove", op_sync(op_webstorage_remove)),
("op_webstorage_clear", op_sync(op_webstorage_clear)),
(
"op_webstorage_iterate_keys",
op_sync(op_webstorage_iterate_keys),
),
op_webstorage_length::decl(),
op_webstorage_key::decl(),
op_webstorage_set::decl(),
op_webstorage_get::decl(),
op_webstorage_remove::decl(),
op_webstorage_clear::decl(),
op_webstorage_iterate_keys::decl(),
])
.state(move |state| {
if let Some(origin_storage_dir) = &origin_storage_dir {
@ -103,6 +100,7 @@ fn get_webstorage(
Ok(conn)
}
#[op]
pub fn op_webstorage_length(
state: &mut OpState,
persistent: bool,
@ -116,6 +114,7 @@ pub fn op_webstorage_length(
Ok(length)
}
#[op]
pub fn op_webstorage_key(
state: &mut OpState,
index: u32,
@ -140,6 +139,7 @@ pub struct SetArgs {
key_value: String,
}
#[op]
pub fn op_webstorage_set(
state: &mut OpState,
args: SetArgs,
@ -167,6 +167,7 @@ pub fn op_webstorage_set(
Ok(())
}
#[op]
pub fn op_webstorage_get(
state: &mut OpState,
key_name: String,
@ -182,6 +183,7 @@ pub fn op_webstorage_get(
Ok(val)
}
#[op]
pub fn op_webstorage_remove(
state: &mut OpState,
key_name: String,
@ -195,6 +197,7 @@ pub fn op_webstorage_remove(
Ok(())
}
#[op]
pub fn op_webstorage_clear(
state: &mut OpState,
persistent: bool,
@ -208,6 +211,7 @@ pub fn op_webstorage_clear(
Ok(())
}
#[op]
pub fn op_webstorage_iterate_keys(
state: &mut OpState,
persistent: bool,

17
ops/Cargo.toml Normal file
View file

@ -0,0 +1,17 @@
[package]
name = "deno_ops"
version = "0.1.1"
edition = "2021"
license = "MIT"
readme = "README.md"
description = "Proc macro for writing Deno Ops"
[lib]
path = "./lib.rs"
proc-macro = true
[dependencies]
proc-macro-crate = "1.1.3"
proc-macro2 = "1"
quote = "1"
syn = { version = "1", features = ["full", "extra-traits"] }

16
ops/README.md Normal file
View file

@ -0,0 +1,16 @@
# deno_ops
`proc_macro` for generating highly optimized V8 functions from Deno ops.
```rust
// Declare an op.
#[op]
pub fn op_add(_: &mut OpState, a: i32, b: i32) -> Result<i32, AnyError> {
Ok(a + b)
}
// Register with an extension.
Extension::builder()
.ops(vec![op_add::decl()])
.build();
```

264
ops/lib.rs Normal file
View file

@ -0,0 +1,264 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
use proc_macro::TokenStream;
use proc_macro2::Span;
use proc_macro2::TokenStream as TokenStream2;
use proc_macro_crate::crate_name;
use proc_macro_crate::FoundCrate;
use quote::quote;
use syn::Ident;
// Identifer to the `deno_core` crate.
//
// If macro called in deno_core, `crate` is used.
// If macro called outside deno_core, `deno_core` OR the renamed
// version from Cargo.toml is used.
fn core_import() -> TokenStream2 {
let found_crate =
crate_name("deno_core").expect("deno_core not present in `Cargo.toml`");
match found_crate {
FoundCrate::Itself => {
// TODO(@littledivy): This won't work for `deno_core` examples
// since `crate` does not refer to `deno_core`.
// examples must re-export deno_core to make this work
// until Span inspection APIs are stabalized.
//
// https://github.com/rust-lang/rust/issues/54725
quote!(crate)
}
FoundCrate::Name(name) => {
let ident = Ident::new(&name, Span::call_site());
quote!(#ident)
}
}
}
#[proc_macro_attribute]
pub fn op(_attr: TokenStream, item: TokenStream) -> TokenStream {
let func = syn::parse::<syn::ItemFn>(item).expect("expected a function");
let name = &func.sig.ident;
let generics = &func.sig.generics;
let type_params = &func.sig.generics.params;
let where_clause = &func.sig.generics.where_clause;
// Preserve the original func as op_foo::call()
let original_func = {
let mut func = func.clone();
func.sig.ident = quote::format_ident!("call");
func
};
let core = core_import();
let v8_body = if func.sig.asyncness.is_some() {
codegen_v8_async(&core, &func)
} else {
codegen_v8_sync(&core, &func)
};
// Generate wrapper
quote! {
#[allow(non_camel_case_types)]
pub struct #name;
impl #name {
pub fn name() -> &'static str {
stringify!(#name)
}
pub fn v8_cb #generics () -> #core::v8::FunctionCallback #where_clause {
use #core::v8::MapFnTo;
Self::v8_func::<#type_params>.map_fn_to()
}
pub fn decl #generics () -> (&'static str, #core::v8::FunctionCallback) #where_clause {
(Self::name(), Self::v8_cb::<#type_params>())
}
#[inline]
#original_func
pub fn v8_func #generics (
scope: &mut #core::v8::HandleScope,
args: #core::v8::FunctionCallbackArguments,
mut rv: #core::v8::ReturnValue,
) #where_clause {
#v8_body
}
}
}.into()
}
/// Generate the body of a v8 func for an async op
fn codegen_v8_async(core: &TokenStream2, f: &syn::ItemFn) -> TokenStream2 {
let a = codegen_arg(core, &f.sig.inputs[1], "a", 2);
let b = codegen_arg(core, &f.sig.inputs[2], "b", 3);
let type_params = &f.sig.generics.params;
quote! {
use #core::futures::FutureExt;
// SAFETY: Called from Deno.core.opAsync. Which retrieves the index using opId table.
let op_id = unsafe {
#core::v8::Local::<#core::v8::Integer>::cast(args.get(0))
}.value() as usize;
let promise_id = args.get(1);
let promise_id = #core::v8::Local::<#core::v8::Integer>::try_from(promise_id)
.map(|l| l.value() as #core::PromiseId)
.map_err(#core::anyhow::Error::from);
// Fail if promise id invalid (not an int)
let promise_id: #core::PromiseId = match promise_id {
Ok(promise_id) => promise_id,
Err(err) => {
#core::_ops::throw_type_error(scope, format!("invalid promise id: {}", err));
return;
}
};
#a
#b
// SAFETY: Unchecked cast to external since #core guarantees args.data() is a v8 External.
let state_refcell_raw = unsafe {
#core::v8::Local::<#core::v8::External>::cast(args.data().unwrap_unchecked())
}.value();
// SAFETY: The Rc<RefCell<OpState>> is functionally pinned and is tied to the isolate's lifetime
let state = unsafe {
let ptr = state_refcell_raw as *const std::cell::RefCell<#core::OpState>;
// Increment so it will later be decremented/dropped by the underlaying func it is moved to
std::rc::Rc::increment_strong_count(ptr);
std::rc::Rc::from_raw(ptr)
};
// Track async call & get copy of get_error_class_fn
let get_class = {
let state = state.borrow();
state.tracker.track_async(op_id);
state.get_error_class_fn
};
#core::_ops::queue_async_op(scope, async move {
let result = Self::call::<#type_params>(state, a, b).await;
(promise_id, op_id, #core::_ops::to_op_result(get_class, result))
});
}
}
/// Generate the body of a v8 func for a sync op
fn codegen_v8_sync(core: &TokenStream2, f: &syn::ItemFn) -> TokenStream2 {
let a = codegen_arg(core, &f.sig.inputs[1], "a", 1);
let b = codegen_arg(core, &f.sig.inputs[2], "b", 2);
let ret = codegen_sync_ret(core, &f.sig.output);
let type_params = &f.sig.generics.params;
quote! {
// SAFETY: Called from Deno.core.opSync. Which retrieves the index using opId table.
let op_id = unsafe {
#core::v8::Local::<#core::v8::Integer>::cast(args.get(0)).value()
} as usize;
#a
#b
// SAFETY: Unchecked cast to external since #core guarantees args.data() is a v8 External.
let state_refcell_raw = unsafe {
#core::v8::Local::<#core::v8::External>::cast(args.data().unwrap_unchecked())
}.value();
// SAFETY: The Rc<RefCell<OpState>> is functionally pinned and is tied to the isolate's lifetime
let state = unsafe { &*(state_refcell_raw as *const std::cell::RefCell<#core::OpState>) };
let op_state = &mut state.borrow_mut();
let result = Self::call::<#type_params>(op_state, a, b);
op_state.tracker.track_sync(op_id);
#ret
}
}
fn codegen_arg(
core: &TokenStream2,
arg: &syn::FnArg,
name: &str,
idx: i32,
) -> TokenStream2 {
let ident = quote::format_ident!("{name}");
let pat = match arg {
syn::FnArg::Typed(pat) => &pat.pat,
_ => unreachable!(),
};
// Fast path if arg should be skipped
if matches!(**pat, syn::Pat::Wild(_)) {
return quote! { let #ident = (); };
}
// Otherwise deserialize it via serde_v8
quote! {
let #ident = args.get(#idx);
let #ident = match #core::serde_v8::from_v8(scope, #ident) {
Ok(v) => v,
Err(err) => {
let msg = format!("Error parsing args: {}", #core::anyhow::Error::from(err));
return #core::_ops::throw_type_error(scope, msg);
}
};
}
}
fn codegen_sync_ret(
core: &TokenStream2,
output: &syn::ReturnType,
) -> TokenStream2 {
let ret_type = match output {
// Func with no return no-ops
syn::ReturnType::Default => return quote! { let ret = (); },
// Func with a return Result<T, E>
syn::ReturnType::Type(_, ty) => ty,
};
// Optimize Result<(), Err> to skip serde_v8 when Ok(...)
let ok_block = if is_unit_result(&**ret_type) {
quote! {}
} else {
quote! {
let ret = #core::serde_v8::to_v8(scope, v).unwrap();
rv.set(ret);
}
};
quote! {
match result {
Ok(v) => {
#ok_block
},
Err(err) => {
let err = #core::OpError::new(op_state.get_error_class_fn, err);
rv.set(#core::serde_v8::to_v8(scope, err).unwrap());
},
};
}
}
/// Detects if a type is of the form Result<(), Err>
fn is_unit_result(ty: &syn::Type) -> bool {
let path = match ty {
syn::Type::Path(ref path) => path,
_ => return false,
};
let maybe_result = path.path.segments.first().expect("Invalid return type.");
if maybe_result.ident != "Result" {
return false;
}
assert!(!maybe_result.arguments.is_empty());
let args = match &maybe_result.arguments {
syn::PathArguments::AngleBracketed(args) => args,
_ => unreachable!(),
};
match args.args.first().unwrap() {
syn::GenericArgument::Type(syn::Type::Tuple(ty)) => ty.elems.is_empty(),
_ => false,
}
}

View file

@ -8,8 +8,8 @@ use deno_core::error::bad_resource_id;
use deno_core::error::custom_error;
use deno_core::error::type_error;
use deno_core::error::AnyError;
use deno_core::op_async;
use deno_core::op_sync;
use deno_core::op;
use deno_core::Extension;
use deno_core::OpState;
use deno_core::RcRef;
@ -38,59 +38,59 @@ use deno_core::error::not_supported;
pub fn init() -> Extension {
Extension::builder()
.ops(vec![
("op_open_sync", op_sync(op_open_sync)),
("op_open_async", op_async(op_open_async)),
("op_seek_sync", op_sync(op_seek_sync)),
("op_seek_async", op_async(op_seek_async)),
("op_fdatasync_sync", op_sync(op_fdatasync_sync)),
("op_fdatasync_async", op_async(op_fdatasync_async)),
("op_fsync_sync", op_sync(op_fsync_sync)),
("op_fsync_async", op_async(op_fsync_async)),
("op_fstat_sync", op_sync(op_fstat_sync)),
("op_fstat_async", op_async(op_fstat_async)),
("op_flock_sync", op_sync(op_flock_sync)),
("op_flock_async", op_async(op_flock_async)),
("op_funlock_sync", op_sync(op_funlock_sync)),
("op_funlock_async", op_async(op_funlock_async)),
("op_umask", op_sync(op_umask)),
("op_chdir", op_sync(op_chdir)),
("op_mkdir_sync", op_sync(op_mkdir_sync)),
("op_mkdir_async", op_async(op_mkdir_async)),
("op_chmod_sync", op_sync(op_chmod_sync)),
("op_chmod_async", op_async(op_chmod_async)),
("op_chown_sync", op_sync(op_chown_sync)),
("op_chown_async", op_async(op_chown_async)),
("op_remove_sync", op_sync(op_remove_sync)),
("op_remove_async", op_async(op_remove_async)),
("op_copy_file_sync", op_sync(op_copy_file_sync)),
("op_copy_file_async", op_async(op_copy_file_async)),
("op_stat_sync", op_sync(op_stat_sync)),
("op_stat_async", op_async(op_stat_async)),
("op_realpath_sync", op_sync(op_realpath_sync)),
("op_realpath_async", op_async(op_realpath_async)),
("op_read_dir_sync", op_sync(op_read_dir_sync)),
("op_read_dir_async", op_async(op_read_dir_async)),
("op_rename_sync", op_sync(op_rename_sync)),
("op_rename_async", op_async(op_rename_async)),
("op_link_sync", op_sync(op_link_sync)),
("op_link_async", op_async(op_link_async)),
("op_symlink_sync", op_sync(op_symlink_sync)),
("op_symlink_async", op_async(op_symlink_async)),
("op_read_link_sync", op_sync(op_read_link_sync)),
("op_read_link_async", op_async(op_read_link_async)),
("op_ftruncate_sync", op_sync(op_ftruncate_sync)),
("op_ftruncate_async", op_async(op_ftruncate_async)),
("op_truncate_sync", op_sync(op_truncate_sync)),
("op_truncate_async", op_async(op_truncate_async)),
("op_make_temp_dir_sync", op_sync(op_make_temp_dir_sync)),
("op_make_temp_dir_async", op_async(op_make_temp_dir_async)),
("op_make_temp_file_sync", op_sync(op_make_temp_file_sync)),
("op_make_temp_file_async", op_async(op_make_temp_file_async)),
("op_cwd", op_sync(op_cwd)),
("op_futime_sync", op_sync(op_futime_sync)),
("op_futime_async", op_async(op_futime_async)),
("op_utime_sync", op_sync(op_utime_sync)),
("op_utime_async", op_async(op_utime_async)),
op_open_sync::decl(),
op_open_async::decl(),
op_seek_sync::decl(),
op_seek_async::decl(),
op_fdatasync_sync::decl(),
op_fdatasync_async::decl(),
op_fsync_sync::decl(),
op_fsync_async::decl(),
op_fstat_sync::decl(),
op_fstat_async::decl(),
op_flock_sync::decl(),
op_flock_async::decl(),
op_funlock_sync::decl(),
op_funlock_async::decl(),
op_umask::decl(),
op_chdir::decl(),
op_mkdir_sync::decl(),
op_mkdir_async::decl(),
op_chmod_sync::decl(),
op_chmod_async::decl(),
op_chown_sync::decl(),
op_chown_async::decl(),
op_remove_sync::decl(),
op_remove_async::decl(),
op_copy_file_sync::decl(),
op_copy_file_async::decl(),
op_stat_sync::decl(),
op_stat_async::decl(),
op_realpath_sync::decl(),
op_realpath_async::decl(),
op_read_dir_sync::decl(),
op_read_dir_async::decl(),
op_rename_sync::decl(),
op_rename_async::decl(),
op_link_sync::decl(),
op_link_async::decl(),
op_symlink_sync::decl(),
op_symlink_async::decl(),
op_read_link_sync::decl(),
op_read_link_async::decl(),
op_ftruncate_sync::decl(),
op_ftruncate_async::decl(),
op_truncate_sync::decl(),
op_truncate_async::decl(),
op_make_temp_dir_sync::decl(),
op_make_temp_dir_async::decl(),
op_make_temp_file_sync::decl(),
op_make_temp_file_async::decl(),
op_cwd::decl(),
op_futime_sync::decl(),
op_futime_async::decl(),
op_utime_sync::decl(),
op_utime_async::decl(),
])
.build()
}
@ -157,6 +157,7 @@ fn open_helper(
Ok((path, open_options))
}
#[op]
fn op_open_sync(
state: &mut OpState,
args: OpenArgs,
@ -172,6 +173,7 @@ fn op_open_sync(
Ok(rid)
}
#[op]
async fn op_open_async(
state: Rc<RefCell<OpState>>,
args: OpenArgs,
@ -214,6 +216,7 @@ fn seek_helper(args: SeekArgs) -> Result<(u32, SeekFrom), AnyError> {
Ok((rid, seek_from))
}
#[op]
fn op_seek_sync(
state: &mut OpState,
args: SeekArgs,
@ -229,6 +232,7 @@ fn op_seek_sync(
Ok(pos)
}
#[op]
async fn op_seek_async(
state: Rc<RefCell<OpState>>,
args: SeekArgs,
@ -253,6 +257,7 @@ async fn op_seek_async(
Ok(pos)
}
#[op]
fn op_fdatasync_sync(
state: &mut OpState,
rid: ResourceId,
@ -265,6 +270,7 @@ fn op_fdatasync_sync(
Ok(())
}
#[op]
async fn op_fdatasync_async(
state: Rc<RefCell<OpState>>,
rid: ResourceId,
@ -287,6 +293,7 @@ async fn op_fdatasync_async(
Ok(())
}
#[op]
fn op_fsync_sync(
state: &mut OpState,
rid: ResourceId,
@ -299,6 +306,7 @@ fn op_fsync_sync(
Ok(())
}
#[op]
async fn op_fsync_async(
state: Rc<RefCell<OpState>>,
rid: ResourceId,
@ -321,6 +329,7 @@ async fn op_fsync_async(
Ok(())
}
#[op]
fn op_fstat_sync(
state: &mut OpState,
rid: ResourceId,
@ -333,6 +342,7 @@ fn op_fstat_sync(
Ok(get_stat(metadata))
}
#[op]
async fn op_fstat_async(
state: Rc<RefCell<OpState>>,
rid: ResourceId,
@ -355,6 +365,7 @@ async fn op_fstat_async(
Ok(get_stat(metadata))
}
#[op]
fn op_flock_sync(
state: &mut OpState,
rid: ResourceId,
@ -376,6 +387,7 @@ fn op_flock_sync(
})
}
#[op]
async fn op_flock_async(
state: Rc<RefCell<OpState>>,
rid: ResourceId,
@ -416,6 +428,7 @@ async fn op_flock_async(
.await?
}
#[op]
fn op_funlock_sync(
state: &mut OpState,
rid: ResourceId,
@ -433,6 +446,7 @@ fn op_funlock_sync(
})
}
#[op]
async fn op_funlock_async(
state: Rc<RefCell<OpState>>,
rid: ResourceId,
@ -469,6 +483,7 @@ async fn op_funlock_async(
.await?
}
#[op]
fn op_umask(
state: &mut OpState,
mask: Option<u32>,
@ -501,6 +516,7 @@ fn op_umask(
}
}
#[op]
fn op_chdir(
state: &mut OpState,
directory: String,
@ -522,6 +538,7 @@ pub struct MkdirArgs {
mode: Option<u32>,
}
#[op]
fn op_mkdir_sync(
state: &mut OpState,
args: MkdirArgs,
@ -544,6 +561,7 @@ fn op_mkdir_sync(
Ok(())
}
#[op]
async fn op_mkdir_async(
state: Rc<RefCell<OpState>>,
args: MkdirArgs,
@ -582,6 +600,7 @@ pub struct ChmodArgs {
mode: u32,
}
#[op]
fn op_chmod_sync(
state: &mut OpState,
args: ChmodArgs,
@ -611,6 +630,7 @@ fn op_chmod_sync(
}
}
#[op]
async fn op_chmod_async(
state: Rc<RefCell<OpState>>,
args: ChmodArgs,
@ -656,6 +676,7 @@ pub struct ChownArgs {
gid: Option<u32>,
}
#[op]
fn op_chown_sync(
state: &mut OpState,
args: ChownArgs,
@ -690,6 +711,7 @@ fn op_chown_sync(
}
}
#[op]
async fn op_chown_async(
state: Rc<RefCell<OpState>>,
args: ChownArgs,
@ -738,6 +760,7 @@ pub struct RemoveArgs {
recursive: bool,
}
#[op]
fn op_remove_sync(
state: &mut OpState,
args: RemoveArgs,
@ -783,6 +806,7 @@ fn op_remove_sync(
Ok(())
}
#[op]
async fn op_remove_async(
state: Rc<RefCell<OpState>>,
args: RemoveArgs,
@ -841,6 +865,7 @@ pub struct CopyFileArgs {
to: String,
}
#[op]
fn op_copy_file_sync(
state: &mut OpState,
args: CopyFileArgs,
@ -879,6 +904,7 @@ fn op_copy_file_sync(
Ok(())
}
#[op]
async fn op_copy_file_async(
state: Rc<RefCell<OpState>>,
args: CopyFileArgs,
@ -1007,6 +1033,7 @@ pub struct StatArgs {
lstat: bool,
}
#[op]
fn op_stat_sync(
state: &mut OpState,
args: StatArgs,
@ -1027,6 +1054,7 @@ fn op_stat_sync(
Ok(get_stat(metadata))
}
#[op]
async fn op_stat_async(
state: Rc<RefCell<OpState>>,
args: StatArgs,
@ -1056,6 +1084,7 @@ async fn op_stat_async(
.unwrap()
}
#[op]
fn op_realpath_sync(
state: &mut OpState,
path: String,
@ -1077,6 +1106,7 @@ fn op_realpath_sync(
Ok(realpath_str)
}
#[op]
async fn op_realpath_async(
state: Rc<RefCell<OpState>>,
path: String,
@ -1114,6 +1144,7 @@ pub struct DirEntry {
is_symlink: bool,
}
#[op]
fn op_read_dir_sync(
state: &mut OpState,
path: String,
@ -1154,6 +1185,7 @@ fn op_read_dir_sync(
Ok(entries)
}
#[op]
async fn op_read_dir_async(
state: Rc<RefCell<OpState>>,
path: String,
@ -1206,6 +1238,7 @@ pub struct RenameArgs {
newpath: String,
}
#[op]
fn op_rename_sync(
state: &mut OpState,
args: RenameArgs,
@ -1234,6 +1267,7 @@ fn op_rename_sync(
Ok(())
}
#[op]
async fn op_rename_async(
state: Rc<RefCell<OpState>>,
args: RenameArgs,
@ -1279,6 +1313,7 @@ pub struct LinkArgs {
newpath: String,
}
#[op]
fn op_link_sync(
state: &mut OpState,
args: LinkArgs,
@ -1309,6 +1344,7 @@ fn op_link_sync(
Ok(())
}
#[op]
async fn op_link_async(
state: Rc<RefCell<OpState>>,
args: LinkArgs,
@ -1362,6 +1398,7 @@ pub struct SymlinkOptions {
_type: String,
}
#[op]
fn op_symlink_sync(
state: &mut OpState,
args: SymlinkArgs,
@ -1423,6 +1460,7 @@ fn op_symlink_sync(
}
}
#[op]
async fn op_symlink_async(
state: Rc<RefCell<OpState>>,
args: SymlinkArgs,
@ -1487,6 +1525,7 @@ async fn op_symlink_async(
.unwrap()
}
#[op]
fn op_read_link_sync(
state: &mut OpState,
path: String,
@ -1510,6 +1549,7 @@ fn op_read_link_sync(
Ok(targetstr)
}
#[op]
async fn op_read_link_async(
state: Rc<RefCell<OpState>>,
path: String,
@ -1545,6 +1585,7 @@ pub struct FtruncateArgs {
len: i32,
}
#[op]
fn op_ftruncate_sync(
state: &mut OpState,
args: FtruncateArgs,
@ -1559,6 +1600,7 @@ fn op_ftruncate_sync(
Ok(())
}
#[op]
async fn op_ftruncate_async(
state: Rc<RefCell<OpState>>,
args: FtruncateArgs,
@ -1591,6 +1633,7 @@ pub struct TruncateArgs {
len: u64,
}
#[op]
fn op_truncate_sync(
state: &mut OpState,
args: TruncateArgs,
@ -1616,6 +1659,7 @@ fn op_truncate_sync(
Ok(())
}
#[op]
async fn op_truncate_async(
state: Rc<RefCell<OpState>>,
args: TruncateArgs,
@ -1699,6 +1743,7 @@ pub struct MakeTempArgs {
suffix: Option<String>,
}
#[op]
fn op_make_temp_dir_sync(
state: &mut OpState,
args: MakeTempArgs,
@ -1728,6 +1773,7 @@ fn op_make_temp_dir_sync(
Ok(path_str)
}
#[op]
async fn op_make_temp_dir_async(
state: Rc<RefCell<OpState>>,
args: MakeTempArgs,
@ -1762,6 +1808,7 @@ async fn op_make_temp_dir_async(
.unwrap()
}
#[op]
fn op_make_temp_file_sync(
state: &mut OpState,
args: MakeTempArgs,
@ -1791,6 +1838,7 @@ fn op_make_temp_file_sync(
Ok(path_str)
}
#[op]
async fn op_make_temp_file_async(
state: Rc<RefCell<OpState>>,
args: MakeTempArgs,
@ -1833,6 +1881,7 @@ pub struct FutimeArgs {
mtime: (i64, u32),
}
#[op]
fn op_futime_sync(
state: &mut OpState,
args: FutimeArgs,
@ -1856,6 +1905,7 @@ fn op_futime_sync(
Ok(())
}
#[op]
async fn op_futime_async(
state: Rc<RefCell<OpState>>,
args: FutimeArgs,
@ -1904,6 +1954,7 @@ pub struct UtimeArgs {
mtime: (i64, u32),
}
#[op]
fn op_utime_sync(
state: &mut OpState,
args: UtimeArgs,
@ -1922,6 +1973,7 @@ fn op_utime_sync(
Ok(())
}
#[op]
async fn op_utime_async(
state: Rc<RefCell<OpState>>,
args: UtimeArgs,
@ -1949,6 +2001,7 @@ async fn op_utime_async(
.unwrap()
}
#[op]
fn op_cwd(state: &mut OpState, _: (), _: ()) -> Result<String, AnyError> {
let path = current_dir()?;
state

View file

@ -11,8 +11,8 @@ use deno_core::RcRef;
use deno_core::Resource;
use deno_core::ResourceId;
use deno_core::op_async;
use deno_core::op_sync;
use deno_core::op;
use deno_core::Extension;
use notify::event::Event as NotifyEvent;
use notify::Error as NotifyError;
@ -31,10 +31,7 @@ use tokio::sync::mpsc;
pub fn init() -> Extension {
Extension::builder()
.ops(vec![
("op_fs_events_open", op_sync(op_fs_events_open)),
("op_fs_events_poll", op_async(op_fs_events_poll)),
])
.ops(vec![op_fs_events_open::decl(), op_fs_events_poll::decl()])
.build()
}
@ -97,6 +94,7 @@ pub struct OpenArgs {
paths: Vec<String>,
}
#[op]
fn op_fs_events_open(
state: &mut OpState,
args: OpenArgs,
@ -131,6 +129,7 @@ fn op_fs_events_open(
Ok(rid)
}
#[op]
async fn op_fs_events_poll(
state: Rc<RefCell<OpState>>,
rid: ResourceId,

View file

@ -2,7 +2,7 @@ use std::rc::Rc;
use deno_core::error::bad_resource_id;
use deno_core::error::AnyError;
use deno_core::op_sync;
use deno_core::op;
use deno_core::Extension;
use deno_core::OpState;
use deno_core::ResourceId;
@ -12,10 +12,11 @@ use deno_net::ops_tls::TlsStreamResource;
pub fn init() -> Extension {
Extension::builder()
.ops(vec![("op_http_start", op_sync(op_http_start))])
.ops(vec![op_http_start::decl()])
.build()
}
#[op]
fn op_http_start(
state: &mut OpState,
tcp_stream_rid: ResourceId,

View file

@ -3,7 +3,7 @@
use deno_core::error::not_supported;
use deno_core::error::resource_unavailable;
use deno_core::error::AnyError;
use deno_core::op_sync;
use deno_core::op;
use deno_core::AsyncMutFuture;
use deno_core::AsyncRefCell;
use deno_core::AsyncResult;
@ -69,10 +69,7 @@ static STDERR_HANDLE: Lazy<StdFile> = Lazy::new(|| unsafe {
pub fn init() -> Extension {
Extension::builder()
.ops(vec![
("op_read_sync", op_sync(op_read_sync)),
("op_write_sync", op_sync(op_write_sync)),
])
.ops(vec![op_read_sync::decl(), op_write_sync::decl()])
.build()
}
@ -354,6 +351,7 @@ impl Resource for StdFileResource {
}
}
#[op]
fn op_read_sync(
state: &mut OpState,
rid: ResourceId,
@ -368,6 +366,7 @@ fn op_read_sync(
})
}
#[op]
fn op_write_sync(
state: &mut OpState,
rid: ResourceId,

View file

@ -3,7 +3,7 @@
use super::utils::into_string;
use crate::permissions::Permissions;
use deno_core::error::{type_error, AnyError};
use deno_core::op_sync;
use deno_core::op;
use deno_core::url::Url;
use deno_core::Extension;
use deno_core::OpState;
@ -17,19 +17,19 @@ use std::sync::Arc;
pub fn init(maybe_exit_code: Option<Arc<AtomicI32>>) -> Extension {
Extension::builder()
.ops(vec![
("op_env", op_sync(op_env)),
("op_exec_path", op_sync(op_exec_path)),
("op_exit", op_sync(op_exit)),
("op_delete_env", op_sync(op_delete_env)),
("op_get_env", op_sync(op_get_env)),
("op_getuid", op_sync(op_getuid)),
("op_hostname", op_sync(op_hostname)),
("op_loadavg", op_sync(op_loadavg)),
("op_network_interfaces", op_sync(op_network_interfaces)),
("op_os_release", op_sync(op_os_release)),
("op_set_env", op_sync(op_set_env)),
("op_set_exit_code", op_sync(op_set_exit_code)),
("op_system_memory_info", op_sync(op_system_memory_info)),
op_env::decl(),
op_exec_path::decl(),
op_exit::decl(),
op_delete_env::decl(),
op_get_env::decl(),
op_getuid::decl(),
op_hostname::decl(),
op_loadavg::decl(),
op_network_interfaces::decl(),
op_os_release::decl(),
op_set_env::decl(),
op_set_exit_code::decl(),
op_system_memory_info::decl(),
])
.state(move |state| {
let exit_code = maybe_exit_code.clone().unwrap_or_default();
@ -39,6 +39,7 @@ pub fn init(maybe_exit_code: Option<Arc<AtomicI32>>) -> Extension {
.build()
}
#[op]
fn op_exec_path(state: &mut OpState, _: (), _: ()) -> Result<String, AnyError> {
let current_exe = env::current_exe().unwrap();
state
@ -53,6 +54,7 @@ fn op_exec_path(state: &mut OpState, _: (), _: ()) -> Result<String, AnyError> {
into_string(path.into_os_string())
}
#[op]
fn op_set_env(
state: &mut OpState,
key: String,
@ -68,6 +70,7 @@ fn op_set_env(
Ok(())
}
#[op]
fn op_env(
state: &mut OpState,
_: (),
@ -77,6 +80,7 @@ fn op_env(
Ok(env::vars().collect())
}
#[op]
fn op_get_env(
state: &mut OpState,
key: String,
@ -93,6 +97,7 @@ fn op_get_env(
Ok(r)
}
#[op]
fn op_delete_env(
state: &mut OpState,
key: String,
@ -106,6 +111,7 @@ fn op_delete_env(
Ok(())
}
#[op]
fn op_set_exit_code(
state: &mut OpState,
code: i32,
@ -115,11 +121,13 @@ fn op_set_exit_code(
Ok(())
}
#[op]
fn op_exit(state: &mut OpState, _: (), _: ()) -> Result<(), AnyError> {
let code = state.borrow::<Arc<AtomicI32>>().load(Relaxed);
std::process::exit(code)
}
#[op]
fn op_loadavg(
state: &mut OpState,
_: (),
@ -133,6 +141,7 @@ fn op_loadavg(
}
}
#[op]
fn op_hostname(state: &mut OpState, _: (), _: ()) -> Result<String, AnyError> {
super::check_unstable(state, "Deno.hostname");
state.borrow_mut::<Permissions>().env.check_all()?;
@ -140,6 +149,7 @@ fn op_hostname(state: &mut OpState, _: (), _: ()) -> Result<String, AnyError> {
Ok(hostname)
}
#[op]
fn op_os_release(
state: &mut OpState,
_: (),
@ -151,6 +161,7 @@ fn op_os_release(
Ok(release)
}
#[op]
fn op_network_interfaces(
state: &mut OpState,
_: (),
@ -218,6 +229,7 @@ struct MemInfo {
pub swap_free: u64,
}
#[op]
fn op_system_memory_info(
state: &mut OpState,
_: (),
@ -240,6 +252,7 @@ fn op_system_memory_info(
}
#[cfg(not(windows))]
#[op]
fn op_getuid(
state: &mut OpState,
_: (),
@ -251,6 +264,7 @@ fn op_getuid(
}
#[cfg(windows)]
#[op]
fn op_getuid(
state: &mut OpState,
_: (),

View file

@ -4,7 +4,7 @@ use crate::permissions::Permissions;
use deno_core::error::custom_error;
use deno_core::error::uri_error;
use deno_core::error::AnyError;
use deno_core::op_sync;
use deno_core::op;
use deno_core::url;
use deno_core::Extension;
use deno_core::OpState;
@ -14,9 +14,9 @@ use std::path::Path;
pub fn init() -> Extension {
Extension::builder()
.ops(vec![
("op_query_permission", op_sync(op_query_permission)),
("op_revoke_permission", op_sync(op_revoke_permission)),
("op_request_permission", op_sync(op_request_permission)),
op_query_permission::decl(),
op_revoke_permission::decl(),
op_request_permission::decl(),
])
.build()
}
@ -30,6 +30,7 @@ pub struct PermissionArgs {
command: Option<String>,
}
#[op]
pub fn op_query_permission(
state: &mut OpState,
args: PermissionArgs,
@ -61,6 +62,7 @@ pub fn op_query_permission(
Ok(perm.to_string())
}
#[op]
pub fn op_revoke_permission(
state: &mut OpState,
args: PermissionArgs,
@ -92,6 +94,7 @@ pub fn op_revoke_permission(
Ok(perm.to_string())
}
#[op]
pub fn op_request_permission(
state: &mut OpState,
args: PermissionArgs,

View file

@ -8,8 +8,8 @@ use crate::permissions::Permissions;
use deno_core::error::bad_resource_id;
use deno_core::error::type_error;
use deno_core::error::AnyError;
use deno_core::op_async;
use deno_core::op_sync;
use deno_core::op;
use deno_core::AsyncMutFuture;
use deno_core::AsyncRefCell;
use deno_core::Extension;
@ -29,11 +29,7 @@ use std::os::unix::process::ExitStatusExt;
pub fn init() -> Extension {
Extension::builder()
.ops(vec![
("op_run", op_sync(op_run)),
("op_run_status", op_async(op_run_status)),
("op_kill", op_sync(op_kill)),
])
.ops(vec![op_run::decl(), op_run_status::decl(), op_kill::decl()])
.build()
}
@ -102,6 +98,7 @@ struct RunInfo {
stderr_rid: Option<ResourceId>,
}
#[op]
fn op_run(
state: &mut OpState,
run_args: RunArgs,
@ -226,6 +223,7 @@ struct ProcessStatus {
exit_signal: i32,
}
#[op]
async fn op_run_status(
state: Rc<RefCell<OpState>>,
rid: ResourceId,
@ -303,6 +301,7 @@ pub fn kill(pid: i32, signal: &str) -> Result<(), AnyError> {
}
}
#[op]
fn op_kill(
state: &mut OpState,
pid: i32,

View file

@ -3,14 +3,14 @@
use crate::permissions::Permissions;
use deno_core::anyhow::Context;
use deno_core::error::AnyError;
use deno_core::op_sync;
use deno_core::op;
use deno_core::Extension;
use deno_core::ModuleSpecifier;
use deno_core::OpState;
pub fn init(main_module: ModuleSpecifier) -> Extension {
Extension::builder()
.ops(vec![("op_main_module", op_sync(op_main_module))])
.ops(vec![op_main_module::decl()])
.state(move |state| {
state.put::<ModuleSpecifier>(main_module.clone());
Ok(())
@ -18,6 +18,7 @@ pub fn init(main_module: ModuleSpecifier) -> Extension {
.build()
}
#[op]
fn op_main_module(
state: &mut OpState,
_: (),

View file

@ -4,8 +4,8 @@ use deno_core::error::generic_error;
#[cfg(not(target_os = "windows"))]
use deno_core::error::type_error;
use deno_core::error::AnyError;
use deno_core::op_async;
use deno_core::op_sync;
use deno_core::op;
use deno_core::Extension;
use deno_core::OpState;
use std::cell::RefCell;
@ -31,9 +31,9 @@ use tokio::signal::unix::{signal, Signal, SignalKind};
pub fn init() -> Extension {
Extension::builder()
.ops(vec![
("op_signal_bind", op_sync(op_signal_bind)),
("op_signal_unbind", op_sync(op_signal_unbind)),
("op_signal_poll", op_async(op_signal_poll)),
op_signal_bind::decl(),
op_signal_unbind::decl(),
op_signal_poll::decl(),
])
.build()
}
@ -174,6 +174,7 @@ pub fn signal_str_to_int(s: &str) -> Result<libc::c_int, AnyError> {
}
#[cfg(unix)]
#[op]
fn op_signal_bind(
state: &mut OpState,
sig: String,
@ -195,6 +196,7 @@ fn op_signal_bind(
}
#[cfg(unix)]
#[op]
async fn op_signal_poll(
state: Rc<RefCell<OpState>>,
rid: ResourceId,
@ -214,6 +216,7 @@ async fn op_signal_poll(
}
#[cfg(unix)]
#[op]
pub fn op_signal_unbind(
state: &mut OpState,
rid: ResourceId,
@ -224,6 +227,7 @@ pub fn op_signal_unbind(
}
#[cfg(not(unix))]
#[op]
pub fn op_signal_bind(
_state: &mut OpState,
_: (),
@ -233,6 +237,7 @@ pub fn op_signal_bind(
}
#[cfg(not(unix))]
#[op]
fn op_signal_unbind(
_state: &mut OpState,
_: (),
@ -242,6 +247,7 @@ fn op_signal_unbind(
}
#[cfg(not(unix))]
#[op]
async fn op_signal_poll(
_state: Rc<RefCell<OpState>>,
_: (),

View file

@ -5,7 +5,7 @@ use deno_core::error::bad_resource_id;
use deno_core::error::not_supported;
use deno_core::error::resource_unavailable;
use deno_core::error::AnyError;
use deno_core::op_sync;
use deno_core::op;
use deno_core::Extension;
use deno_core::OpState;
use deno_core::RcRef;
@ -47,9 +47,9 @@ fn get_windows_handle(
pub fn init() -> Extension {
Extension::builder()
.ops(vec![
("op_set_raw", op_sync(op_set_raw)),
("op_isatty", op_sync(op_isatty)),
("op_console_size", op_sync(op_console_size)),
op_set_raw::decl(),
op_isatty::decl(),
op_console_size::decl(),
])
.build()
}
@ -67,6 +67,7 @@ pub struct SetRawArgs {
options: SetRawOptions,
}
#[op]
fn op_set_raw(
state: &mut OpState,
args: SetRawArgs,
@ -211,6 +212,7 @@ fn op_set_raw(
}
}
#[op]
fn op_isatty(
state: &mut OpState,
rid: ResourceId,
@ -245,6 +247,7 @@ struct ConsoleSize {
rows: u32,
}
#[op]
fn op_console_size(
state: &mut OpState,
rid: ResourceId,

View file

@ -5,8 +5,8 @@ mod sync_fetch;
use crate::web_worker::WebWorkerInternalHandle;
use crate::web_worker::WebWorkerType;
use deno_core::error::AnyError;
use deno_core::op_async;
use deno_core::op_sync;
use deno_core::op;
use deno_core::CancelFuture;
use deno_core::Extension;
use deno_core::OpState;
@ -19,16 +19,17 @@ use self::sync_fetch::op_worker_sync_fetch;
pub fn init() -> Extension {
Extension::builder()
.ops(vec![
("op_worker_post_message", op_sync(op_worker_post_message)),
("op_worker_recv_message", op_async(op_worker_recv_message)),
op_worker_post_message::decl(),
op_worker_recv_message::decl(),
// Notify host that guest worker closes.
("op_worker_close", op_sync(op_worker_close)),
("op_worker_get_type", op_sync(op_worker_get_type)),
("op_worker_sync_fetch", op_sync(op_worker_sync_fetch)),
op_worker_close::decl(),
op_worker_get_type::decl(),
op_worker_sync_fetch::decl(),
])
.build()
}
#[op]
fn op_worker_post_message(
state: &mut OpState,
data: JsMessageData,
@ -39,6 +40,7 @@ fn op_worker_post_message(
Ok(())
}
#[op]
async fn op_worker_recv_message(
state: Rc<RefCell<OpState>>,
_: (),
@ -55,6 +57,7 @@ async fn op_worker_recv_message(
.await?
}
#[op]
fn op_worker_close(state: &mut OpState, _: (), _: ()) -> Result<(), AnyError> {
// Notify parent that we're finished
let mut handle = state.borrow_mut::<WebWorkerInternalHandle>().clone();
@ -63,6 +66,7 @@ fn op_worker_close(state: &mut OpState, _: (), _: ()) -> Result<(), AnyError> {
Ok(())
}
#[op]
fn op_worker_get_type(
state: &mut OpState,
_: (),

View file

@ -4,6 +4,7 @@ use crate::web_worker::WebWorkerInternalHandle;
use crate::web_worker::WebWorkerType;
use deno_core::error::type_error;
use deno_core::error::AnyError;
use deno_core::op;
use deno_core::url::Url;
use deno_core::OpState;
use deno_fetch::data_url::DataUrl;
@ -30,6 +31,7 @@ pub struct SyncFetchScript {
script: String,
}
#[op]
pub fn op_worker_sync_fetch(
state: &mut OpState,
scripts: Vec<String>,

View file

@ -13,8 +13,8 @@ use crate::web_worker::WorkerControlEvent;
use crate::web_worker::WorkerId;
use deno_core::error::AnyError;
use deno_core::futures::future::LocalFutureObj;
use deno_core::op_async;
use deno_core::op_sync;
use deno_core::op;
use deno_core::serde::Deserialize;
use deno_core::Extension;
use deno_core::ModuleSpecifier;
@ -122,14 +122,11 @@ pub fn init(
Ok(())
})
.ops(vec![
("op_create_worker", op_sync(op_create_worker)),
(
"op_host_terminate_worker",
op_sync(op_host_terminate_worker),
),
("op_host_post_message", op_sync(op_host_post_message)),
("op_host_recv_ctrl", op_async(op_host_recv_ctrl)),
("op_host_recv_message", op_async(op_host_recv_message)),
op_create_worker::decl(),
op_host_terminate_worker::decl(),
op_host_post_message::decl(),
op_host_recv_ctrl::decl(),
op_host_recv_message::decl(),
])
.build()
}
@ -147,6 +144,7 @@ pub struct CreateWorkerArgs {
}
/// Create worker as the host
#[op]
fn op_create_worker(
state: &mut OpState,
args: CreateWorkerArgs,
@ -263,6 +261,7 @@ fn op_create_worker(
Ok(worker_id)
}
#[op]
fn op_host_terminate_worker(
state: &mut OpState,
id: WorkerId,
@ -317,6 +316,7 @@ fn close_channel(
}
/// Get control event from guest worker as host
#[op]
async fn op_host_recv_ctrl(
state: Rc<RefCell<OpState>>,
id: WorkerId,
@ -348,6 +348,7 @@ async fn op_host_recv_ctrl(
Ok(WorkerControlEvent::Close)
}
#[op]
async fn op_host_recv_message(
state: Rc<RefCell<OpState>>,
id: WorkerId,
@ -373,6 +374,7 @@ async fn op_host_recv_message(
}
/// Post message to guest worker as host
#[op]
fn op_host_post_message(
state: &mut OpState,
id: WorkerId,