diff --git a/Cargo.lock b/Cargo.lock index 20e94e0c9d0f4f..2057017972acc5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -805,6 +805,15 @@ dependencies = [ "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "op_hello_js" +version = "0.1.0" +dependencies = [ + "deno 0.19.0", + "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "os_pipe" version = "0.8.2" diff --git a/Cargo.toml b/Cargo.toml index 0f0b10de471024..f138a7cb9b8ad3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,7 @@ members = [ "cli", "core", + "op_hello_js", "tools/hyper_hello", "deno_typescript", "js", diff --git a/op_hello/Cargo.toml b/op_hello/Cargo.toml new file mode 100644 index 00000000000000..61c6d2c0e22375 --- /dev/null +++ b/op_hello/Cargo.toml @@ -0,0 +1,19 @@ +# This is an imagined crate directory structure for Deno ops. + +[package] +name = "op_hello" +version = "0.1.0" +authors = ["Ryan Dahl "] +edition = "2018" + +# Note: I am explicitly attempting to not have a build.rs file. I think it might +# be unnecessary for each op crate to implement their own. Then again, it might +# be unavoidable... Let's try without first. + +[dependencies] +deno = "0.19.0" +# deno_std is needed because hello_test.ts depends on the "testing/mod.ts" file +# inside of deno_std. +# TODO deno_std is not yet published as crate +deno_std = "0.19.0" + diff --git a/op_hello/src/hello.ts b/op_hello/src/hello.ts new file mode 100644 index 00000000000000..ab4ca02f69a218 --- /dev/null +++ b/op_hello/src/hello.ts @@ -0,0 +1,12 @@ +const OP_HELLO: number = Deno.ops.add("hello"); + +// https://www.typescriptlang.org/docs/handbook/namespaces.html#splitting-across-files +namespace Deno { + /** + * The typedoc here ideally would be presevered automatically in + * lib.deno_runtime.d.ts + */ + export function hello() { + Deno.core.send(OP_HELLO); + } +} diff --git a/op_hello/src/hello_test.ts b/op_hello/src/hello_test.ts new file mode 100644 index 00000000000000..913568f73c6599 --- /dev/null +++ b/op_hello/src/hello_test.ts @@ -0,0 +1,34 @@ +// We need some way to import test modules. +// Attempt one: +// +// import { test } from "../../js/test_util.ts"; +// +// Here it is referencing files across crate boundaries, which will break +// 'cargo package' and means the crate is not useable outside the deno tree. +// This might be okay for a first pass, but it's not the best solution. +// +// Attempt two: +// we invent a new URL for referencing files in other crates. +// this is magic and not browser compatible.. Browser compatibility for +// ops is not so important. +// +// import { test } from "crate://deno_std@0.19.0/testing/mod.ts"; +// +// This is quite nice. But the version of deno_std already specified in +// Cargo.toml. I think we shouldn't repeat it. +import { test } from "crate://deno_std/testing/mod.ts"; + +// If we don't do the //src reorg that I've proposed in #3022, then we might be +// able to have a very elegant URL some day using the deno crate. +// +// import { test } from "crate://deno/std/testing/mod.ts"; + +import "./hello.ts"; + +test("hello test", () => { + Deno.hello(); +}); + +test("hello test2", () => { + Deno.hello(); +}); diff --git a/op_hello/src/lib.rs b/op_hello/src/lib.rs new file mode 100644 index 00000000000000..5d4ef2df8f9aeb --- /dev/null +++ b/op_hello/src/lib.rs @@ -0,0 +1,41 @@ +extern crate deno; +extern crate deno_std; +use deno::*; + +pub fn init(&mut isolate: Isolate) -> Result<(), ErrBox> { + isolate.register_op("hello", op_hello); // register_op defined by #3002 + + // Explicitly link the deno_std crate so it can be used in hello_test.ts + // Its usage looks like this: + // + // import { test } from "crate://deno_std/testing/mod.ts"; + // + // In the future it might make sense to automate this function away, but I think + // it would be prudent to make the crate URL resolution as obvious as + // possible. + isolate.register_crate_url("deno_std", deno_std::get_file); + + // TODO The ability to run typescript doesn't exist in deno core. + isolate.run("src/hello.ts") +} + +fn op_hello(_control_buf: &[u8], _zero_copy_buf: Option) -> CoreOp { + println!("Hello world"); + CoreOp::Sync(Box::new([])) +} + +#[test] +fn rust_test() { + match op_hello() { + CoreOp::Sync(buf) => { + assert_eq!(buf.len(), 0); + } + CoreOp::Async(_) => unreachable!(), + } +} + +#[test] +fn js_test() { + // This should execute src/hello_test.ts + deno_test(); +} diff --git a/op_hello_js/Cargo.toml b/op_hello_js/Cargo.toml new file mode 100644 index 00000000000000..66ff6d39c9dbe2 --- /dev/null +++ b/op_hello_js/Cargo.toml @@ -0,0 +1,23 @@ +# This is an imagined crate directory structure for Deno ops. +# Same as op_hello but done with JS and not TS. + +[package] +name = "op_hello_js" +version = "0.1.0" +authors = ["Ryan Dahl "] +edition = "2018" + +[lib] +path = "lib.rs" + +[dependencies] +deno = { path = "../core", version = "0.19.0" } + +[[example]] +name = "op_hello_example" +path = "examples/hello.rs" + +# tokio is only used for op_hello_example +[dev_dependencies] +futures = "0.1.29" +tokio = "0.1.18" diff --git a/op_hello_js/examples/hello.js b/op_hello_js/examples/hello.js new file mode 100644 index 00000000000000..422b1c9659d6bd --- /dev/null +++ b/op_hello_js/examples/hello.js @@ -0,0 +1 @@ +hello(); diff --git a/op_hello_js/examples/hello.rs b/op_hello_js/examples/hello.rs new file mode 100644 index 00000000000000..5cb802f1a89dbf --- /dev/null +++ b/op_hello_js/examples/hello.rs @@ -0,0 +1,41 @@ +/// To run this benchmark: +/// +/// > DENO_BUILD_MODE=release ./tools/build.py && \ +/// ./target/release/deno_core_http_bench --multi-thread +extern crate deno; +extern crate futures; +extern crate tokio; + +use deno::*; +use futures::future::lazy; +use tokio::prelude::*; + + +fn main() { + let main_future = lazy(move || { + // TODO currently isolate.execute() must be run inside tokio, hence the + // lazy(). It would be nice to not have that contraint. Probably requires + // using v8::MicrotasksPolicy::kExplicit + + let js_source = include_str!("hello.js"); + + let mut isolate = deno::Isolate::new(StartupData::None, false); + let r = op_hello_js::init(&mut isolate); + eprintln!("result r {:?}", r); + let r = isolate.execute("hello.js", js_source); + eprintln!("result r {:?}", r); + + isolate.then(|r| { + js_check(r); + Ok(()) + }) + }); + + tokio::runtime::current_thread::run(main_future); +} + +fn js_check(r: Result<(), ErrBox>) { + if let Err(e) = r { + panic!(e.to_string()); + } +} diff --git a/op_hello_js/hello.js b/op_hello_js/hello.js new file mode 100644 index 00000000000000..b15ab404bd10c1 --- /dev/null +++ b/op_hello_js/hello.js @@ -0,0 +1,6 @@ +// TODO In the future maybe we can extract the op id in the top-level and use a +// constant. But currently it's causing problems with snapshotting. + +function hello() { + Deno.core.send(Deno.core.ops()["hello"]); +} diff --git a/op_hello_js/hello_test.js b/op_hello_js/hello_test.js new file mode 100644 index 00000000000000..5fd5d0c050319e --- /dev/null +++ b/op_hello_js/hello_test.js @@ -0,0 +1,4 @@ +// As opposed to the TypeScript op_hello example, here we want to not rely on +// deno_std, as it uses TypeScript. So here don't use a test runner. +import { hello } from "./hello.js"; +hello(); diff --git a/op_hello_js/lib.rs b/op_hello_js/lib.rs new file mode 100644 index 00000000000000..333eed15415f40 --- /dev/null +++ b/op_hello_js/lib.rs @@ -0,0 +1,27 @@ +extern crate deno; +use deno::*; + +pub fn init(isolate: &mut Isolate) -> Result<(), ErrBox> { + isolate.register_op("hello", op_hello); // register_op defined by #3002 + isolate.execute("hello.js", include_str!("hello.js"))?; + Ok(()) +} + +fn op_hello(_control_buf: &[u8], _zero_copy_buf: Option) -> CoreOp { + println!("Hello world"); + CoreOp::Sync(Box::new([])) +} + +#[test] +fn js_test() { + isolate.execute("hello_test.js") +} + +#[test] +fn rust_test() { + if let CoreOp::Sync(buf) = op_hello() { + assert_eq!(buf.len(), 0); + } else { + unreachable!(); + } +}