summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/basic_state.rs91
-rw-r--r--core/bindings.rs4
-rw-r--r--core/examples/http_bench_bin_ops.rs84
-rw-r--r--core/examples/http_bench_json_ops.rs46
-rw-r--r--core/gotham_state.rs167
-rw-r--r--core/lib.rs8
-rw-r--r--core/modules.rs49
-rw-r--r--core/ops.rs256
-rw-r--r--core/runtime.rs251
9 files changed, 532 insertions, 424 deletions
diff --git a/core/basic_state.rs b/core/basic_state.rs
deleted file mode 100644
index 54b9ee132..000000000
--- a/core/basic_state.rs
+++ /dev/null
@@ -1,91 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-use crate::BufVec;
-use crate::Op;
-use crate::OpId;
-use crate::OpRegistry;
-use crate::OpRouter;
-use crate::OpTable;
-use crate::ResourceTable;
-use std::cell::RefCell;
-use std::collections::HashMap;
-use std::rc::Rc;
-
-/// A minimal state struct for use by tests, examples etc. It contains
-/// an OpTable and ResourceTable, and implements the relevant traits
-/// for working with ops in the most straightforward way possible.
-#[derive(Default)]
-pub struct BasicState {
- pub op_table: RefCell<OpTable<Self>>,
- pub resource_table: RefCell<ResourceTable>,
-}
-
-impl BasicState {
- pub fn new() -> Rc<Self> {
- Default::default()
- }
-}
-
-impl OpRegistry for BasicState {
- fn get_op_catalog(self: Rc<Self>) -> HashMap<String, OpId> {
- self.op_table.borrow().get_op_catalog()
- }
-
- fn register_op<F>(&self, name: &str, op_fn: F) -> OpId
- where
- F: Fn(Rc<Self>, BufVec) -> Op + 'static,
- {
- let mut op_table = self.op_table.borrow_mut();
- let (op_id, prev) = op_table.insert_full(name.to_owned(), Rc::new(op_fn));
- assert!(prev.is_none());
- op_id
- }
-}
-
-impl OpRouter for BasicState {
- fn route_op(self: Rc<Self>, op_id: OpId, bufs: BufVec) -> Op {
- let op_fn = self
- .op_table
- .borrow()
- .get_index(op_id)
- .map(|(_, op_fn)| op_fn.clone())
- .unwrap();
- (op_fn)(self, bufs)
- }
-}
-
-#[test]
-fn test_basic_state_ops() {
- let state = BasicState::new();
-
- let foo_id = state.register_op("foo", |_, _| Op::Sync(b"oof!"[..].into()));
- assert_eq!(foo_id, 1);
-
- let bar_id = state.register_op("bar", |_, _| Op::Sync(b"rab!"[..].into()));
- assert_eq!(bar_id, 2);
-
- let state_ = state.clone();
- let foo_res = state_.route_op(foo_id, Default::default());
- assert!(matches!(foo_res, Op::Sync(buf) if &*buf == b"oof!"));
-
- let state_ = state.clone();
- let bar_res = state_.route_op(bar_id, Default::default());
- assert!(matches!(bar_res, Op::Sync(buf) if &*buf == b"rab!"));
-
- let catalog_res = state.route_op(0, Default::default());
- let mut catalog_entries = match catalog_res {
- Op::Sync(buf) => serde_json::from_slice::<HashMap<String, OpId>>(&buf)
- .map(|map| map.into_iter().collect::<Vec<_>>())
- .unwrap(),
- _ => panic!("unexpected `Op` variant"),
- };
- 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)
- ]
- )
-}
diff --git a/core/bindings.rs b/core/bindings.rs
index d0d916bdc..265906990 100644
--- a/core/bindings.rs
+++ b/core/bindings.rs
@@ -6,6 +6,7 @@ use crate::JsRuntime;
use crate::JsRuntimeState;
use crate::Op;
use crate::OpId;
+use crate::OpTable;
use crate::ZeroCopyBuf;
use futures::future::FutureExt;
use rusty_v8 as v8;
@@ -426,8 +427,7 @@ fn send<'s>(
}
};
- let op_router = state.op_router.clone();
- let op = op_router.route_op(op_id, bufs);
+ let op = OpTable::route_op(op_id, state.op_state.clone(), bufs);
assert_eq!(state.shared.size(), 0);
match op {
Op::Sync(buf) if !buf.is_empty() => {
diff --git a/core/examples/http_bench_bin_ops.rs b/core/examples/http_bench_bin_ops.rs
index 00eb95f44..b29af8b9d 100644
--- a/core/examples/http_bench_bin_ops.rs
+++ b/core/examples/http_bench_bin_ops.rs
@@ -2,11 +2,10 @@
extern crate log;
use deno_core::js_check;
-use deno_core::BasicState;
use deno_core::BufVec;
use deno_core::JsRuntime;
use deno_core::Op;
-use deno_core::OpRegistry;
+use deno_core::OpState;
use deno_core::Script;
use deno_core::StartupData;
use deno_core::ZeroCopyBuf;
@@ -14,6 +13,7 @@ use futures::future::poll_fn;
use futures::future::FutureExt;
use futures::future::TryFuture;
use futures::future::TryFutureExt;
+use std::cell::RefCell;
use std::convert::TryInto;
use std::env;
use std::fmt::Debug;
@@ -78,23 +78,22 @@ impl From<Record> for RecordBuf {
}
fn create_isolate() -> JsRuntime {
- let state = BasicState::new();
- register_op_bin_sync(&state, "listen", op_listen);
- register_op_bin_sync(&state, "close", op_close);
- register_op_bin_async(&state, "accept", op_accept);
- register_op_bin_async(&state, "read", op_read);
- register_op_bin_async(&state, "write", op_write);
-
let startup_data = StartupData::Script(Script {
source: include_str!("http_bench_bin_ops.js"),
filename: "http_bench_bin_ops.js",
});
- JsRuntime::new(state, startup_data, false)
+ let mut isolate = JsRuntime::new(startup_data, false);
+ register_op_bin_sync(&mut isolate, "listen", op_listen);
+ register_op_bin_sync(&mut isolate, "close", op_close);
+ register_op_bin_async(&mut isolate, "accept", op_accept);
+ register_op_bin_async(&mut isolate, "read", op_read);
+ register_op_bin_async(&mut isolate, "write", op_write);
+ isolate
}
fn op_listen(
- state: &BasicState,
+ state: &mut OpState,
_rid: u32,
_bufs: &mut [ZeroCopyBuf],
) -> Result<u32, Error> {
@@ -102,36 +101,33 @@ fn op_listen(
let addr = "127.0.0.1:4544".parse::<SocketAddr>().unwrap();
let std_listener = std::net::TcpListener::bind(&addr)?;
let listener = TcpListener::from_std(std_listener)?;
- let rid = state
- .resource_table
- .borrow_mut()
- .add("tcpListener", Box::new(listener));
+ let rid = state.resource_table.add("tcpListener", Box::new(listener));
Ok(rid)
}
fn op_close(
- state: &BasicState,
+ state: &mut OpState,
rid: u32,
_bufs: &mut [ZeroCopyBuf],
) -> Result<u32, Error> {
debug!("close rid={}", rid);
state
.resource_table
- .borrow_mut()
.close(rid)
.map(|_| 0)
.ok_or_else(bad_resource_id)
}
-fn op_accept(
- state: Rc<BasicState>,
+async fn op_accept(
+ state: Rc<RefCell<OpState>>,
rid: u32,
_bufs: BufVec,
-) -> impl TryFuture<Ok = u32, Error = Error> {
+) -> Result<u32, Error> {
debug!("accept rid={}", rid);
poll_fn(move |cx| {
- let resource_table = &mut state.resource_table.borrow_mut();
+ let resource_table = &mut state.borrow_mut().resource_table;
+
let listener = resource_table
.get_mut::<TcpListener>(rid)
.ok_or_else(bad_resource_id)?;
@@ -139,10 +135,11 @@ fn op_accept(
resource_table.add("tcpStream", Box::new(stream))
})
})
+ .await
}
fn op_read(
- state: Rc<BasicState>,
+ state: Rc<RefCell<OpState>>,
rid: u32,
bufs: BufVec,
) -> impl TryFuture<Ok = usize, Error = Error> {
@@ -152,7 +149,8 @@ fn op_read(
debug!("read rid={}", rid);
poll_fn(move |cx| {
- let resource_table = &mut state.resource_table.borrow_mut();
+ let resource_table = &mut state.borrow_mut().resource_table;
+
let stream = resource_table
.get_mut::<TcpStream>(rid)
.ok_or_else(bad_resource_id)?;
@@ -161,7 +159,7 @@ fn op_read(
}
fn op_write(
- state: Rc<BasicState>,
+ state: Rc<RefCell<OpState>>,
rid: u32,
bufs: BufVec,
) -> impl TryFuture<Ok = usize, Error = Error> {
@@ -170,7 +168,8 @@ fn op_write(
debug!("write rid={}", rid);
poll_fn(move |cx| {
- let resource_table = &mut state.resource_table.borrow_mut();
+ let resource_table = &mut state.borrow_mut().resource_table;
+
let stream = resource_table
.get_mut::<TcpStream>(rid)
.ok_or_else(bad_resource_id)?;
@@ -178,35 +177,42 @@ fn op_write(
})
}
-fn register_op_bin_sync<F>(state: &BasicState, name: &'static str, op_fn: F)
-where
- F: Fn(&BasicState, u32, &mut [ZeroCopyBuf]) -> Result<u32, Error> + 'static,
+fn register_op_bin_sync<F>(
+ isolate: &mut JsRuntime,
+ name: &'static str,
+ op_fn: F,
+) where
+ F: Fn(&mut OpState, u32, &mut [ZeroCopyBuf]) -> Result<u32, Error> + 'static,
{
- let base_op_fn = move |state: Rc<BasicState>, mut bufs: BufVec| -> Op {
+ let base_op_fn = move |state: Rc<RefCell<OpState>>, mut bufs: BufVec| -> Op {
let record = Record::from(bufs[0].as_ref());
let is_sync = record.promise_id == 0;
assert!(is_sync);
let zero_copy_bufs = &mut bufs[1..];
- let result: i32 = match op_fn(&state, record.rid, zero_copy_bufs) {
- Ok(r) => r as i32,
- Err(_) => -1,
- };
+ let result: i32 =
+ match op_fn(&mut state.borrow_mut(), record.rid, zero_copy_bufs) {
+ Ok(r) => r as i32,
+ Err(_) => -1,
+ };
let buf = RecordBuf::from(Record { result, ..record })[..].into();
Op::Sync(buf)
};
- state.register_op(name, base_op_fn);
+ isolate.register_op(name, base_op_fn);
}
-fn register_op_bin_async<F, R>(state: &BasicState, name: &'static str, op_fn: F)
-where
- F: Fn(Rc<BasicState>, u32, BufVec) -> R + Copy + 'static,
+fn register_op_bin_async<F, R>(
+ isolate: &mut JsRuntime,
+ name: &'static str,
+ op_fn: F,
+) where
+ F: Fn(Rc<RefCell<OpState>>, u32, BufVec) -> R + Copy + 'static,
R: TryFuture,
R::Ok: TryInto<i32>,
<R::Ok as TryInto<i32>>::Error: Debug,
{
- let base_op_fn = move |state: Rc<BasicState>, bufs: BufVec| -> Op {
+ let base_op_fn = move |state: Rc<RefCell<OpState>>, bufs: BufVec| -> Op {
let mut bufs_iter = bufs.into_iter();
let record_buf = bufs_iter.next().unwrap();
let zero_copy_bufs = bufs_iter.collect::<BufVec>();
@@ -227,7 +233,7 @@ where
Op::Async(fut.boxed_local())
};
- state.register_op(name, base_op_fn);
+ isolate.register_op(name, base_op_fn);
}
fn bad_resource_id() -> Error {
diff --git a/core/examples/http_bench_json_ops.rs b/core/examples/http_bench_json_ops.rs
index de467b8ad..dc0c837e2 100644
--- a/core/examples/http_bench_json_ops.rs
+++ b/core/examples/http_bench_json_ops.rs
@@ -2,17 +2,17 @@
extern crate log;
use deno_core::js_check;
-use deno_core::BasicState;
use deno_core::BufVec;
use deno_core::ErrBox;
use deno_core::JsRuntime;
-use deno_core::OpRegistry;
+use deno_core::OpState;
use deno_core::Script;
use deno_core::StartupData;
use deno_core::ZeroCopyBuf;
use futures::future::poll_fn;
use futures::future::Future;
use serde_json::Value;
+use std::cell::RefCell;
use std::convert::TryInto;
use std::env;
use std::net::SocketAddr;
@@ -42,23 +42,21 @@ impl log::Log for Logger {
}
fn create_isolate() -> JsRuntime {
- let state = BasicState::new();
- state.register_op_json_sync("listen", op_listen);
- state.register_op_json_sync("close", op_close);
- state.register_op_json_async("accept", op_accept);
- state.register_op_json_async("read", op_read);
- state.register_op_json_async("write", op_write);
-
let startup_data = StartupData::Script(Script {
source: include_str!("http_bench_json_ops.js"),
filename: "http_bench_json_ops.js",
});
-
- JsRuntime::new(state, startup_data, false)
+ let mut runtime = JsRuntime::new(startup_data, false);
+ runtime.register_op("listen", deno_core::json_op_sync(op_listen));
+ runtime.register_op("close", deno_core::json_op_sync(op_close));
+ runtime.register_op("accept", deno_core::json_op_async(op_accept));
+ runtime.register_op("read", deno_core::json_op_async(op_read));
+ runtime.register_op("write", deno_core::json_op_async(op_write));
+ runtime
}
fn op_listen(
- state: &BasicState,
+ state: &mut OpState,
_args: Value,
_bufs: &mut [ZeroCopyBuf],
) -> Result<Value, ErrBox> {
@@ -66,15 +64,12 @@ fn op_listen(
let addr = "127.0.0.1:4544".parse::<SocketAddr>().unwrap();
let std_listener = std::net::TcpListener::bind(&addr)?;
let listener = TcpListener::from_std(std_listener)?;
- let rid = state
- .resource_table
- .borrow_mut()
- .add("tcpListener", Box::new(listener));
+ let rid = state.resource_table.add("tcpListener", Box::new(listener));
Ok(serde_json::json!({ "rid": rid }))
}
fn op_close(
- state: &BasicState,
+ state: &mut OpState,
args: Value,
_buf: &mut [ZeroCopyBuf],
) -> Result<Value, ErrBox> {
@@ -86,17 +81,15 @@ fn op_close(
.try_into()
.unwrap();
debug!("close rid={}", rid);
-
state
.resource_table
- .borrow_mut()
.close(rid)
.map(|_| serde_json::json!(()))
.ok_or_else(ErrBox::bad_resource_id)
}
fn op_accept(
- state: Rc<BasicState>,
+ state: Rc<RefCell<OpState>>,
args: Value,
_bufs: BufVec,
) -> impl Future<Output = Result<Value, ErrBox>> {
@@ -110,7 +103,8 @@ fn op_accept(
debug!("accept rid={}", rid);
poll_fn(move |cx| {
- let resource_table = &mut state.resource_table.borrow_mut();
+ let resource_table = &mut state.borrow_mut().resource_table;
+
let listener = resource_table
.get_mut::<TcpListener>(rid)
.ok_or_else(ErrBox::bad_resource_id)?;
@@ -122,7 +116,7 @@ fn op_accept(
}
fn op_read(
- state: Rc<BasicState>,
+ state: Rc<RefCell<OpState>>,
args: Value,
mut bufs: BufVec,
) -> impl Future<Output = Result<Value, ErrBox>> {
@@ -138,7 +132,8 @@ fn op_read(
debug!("read rid={}", rid);
poll_fn(move |cx| -> Poll<Result<Value, ErrBox>> {
- let resource_table = &mut state.resource_table.borrow_mut();
+ let resource_table = &mut state.borrow_mut().resource_table;
+
let stream = resource_table
.get_mut::<TcpStream>(rid)
.ok_or_else(ErrBox::bad_resource_id)?;
@@ -149,7 +144,7 @@ fn op_read(
}
fn op_write(
- state: Rc<BasicState>,
+ state: Rc<RefCell<OpState>>,
args: Value,
bufs: BufVec,
) -> impl Future<Output = Result<Value, ErrBox>> {
@@ -165,7 +160,8 @@ fn op_write(
debug!("write rid={}", rid);
poll_fn(move |cx| {
- let resource_table = &mut state.resource_table.borrow_mut();
+ let resource_table = &mut state.borrow_mut().resource_table;
+
let stream = resource_table
.get_mut::<TcpStream>(rid)
.ok_or_else(ErrBox::bad_resource_id)?;
diff --git a/core/gotham_state.rs b/core/gotham_state.rs
new file mode 100644
index 000000000..94a2d67d4
--- /dev/null
+++ b/core/gotham_state.rs
@@ -0,0 +1,167 @@
+// Forked from Gotham:
+// https://github.com/gotham-rs/gotham/blob/bcbbf8923789e341b7a0e62c59909428ca4e22e2/gotham/src/state/mod.rs
+// Copyright 2017 Gotham Project Developers. MIT license.
+
+use std::any::Any;
+use std::any::TypeId;
+use std::collections::HashMap;
+
+#[derive(Default)]
+pub struct GothamState {
+ data: HashMap<TypeId, Box<dyn Any>>,
+}
+
+impl GothamState {
+ /// Puts a value into the `GothamState` storage. One value of each type is retained.
+ /// Successive calls to `put` will overwrite the existing value of the same
+ /// type.
+ pub fn put<T: 'static>(&mut self, t: T) {
+ let type_id = TypeId::of::<T>();
+ trace!(" inserting record to state for type_id `{:?}`", type_id);
+ self.data.insert(type_id, Box::new(t));
+ }
+
+ /// Determines if the current value exists in `GothamState` storage.
+ pub fn has<T: 'static>(&self) -> bool {
+ let type_id = TypeId::of::<T>();
+ self.data.get(&type_id).is_some()
+ }
+
+ /// Tries to borrow a value from the `GothamState` storage.
+ pub fn try_borrow<T: 'static>(&self) -> Option<&T> {
+ let type_id = TypeId::of::<T>();
+ trace!(" borrowing state data for type_id `{:?}`", type_id);
+ self.data.get(&type_id).and_then(|b| b.downcast_ref())
+ }
+
+ /// Borrows a value from the `GothamState` storage.
+ pub fn borrow<T: 'static>(&self) -> &T {
+ self
+ .try_borrow()
+ .expect("required type is not present in GothamState container")
+ }
+
+ /// Tries to mutably borrow a value from the `GothamState` storage.
+ pub fn try_borrow_mut<T: 'static>(&mut self) -> Option<&mut T> {
+ let type_id = TypeId::of::<T>();
+ trace!(" mutably borrowing state data for type_id `{:?}`", type_id);
+ self.data.get_mut(&type_id).and_then(|b| b.downcast_mut())
+ }
+
+ /// Mutably borrows a value from the `GothamState` storage.
+ pub fn borrow_mut<T: 'static>(&mut self) -> &mut T {
+ self
+ .try_borrow_mut()
+ .expect("required type is not present in GothamState container")
+ }
+
+ /// Tries to move a value out of the `GothamState` storage and return ownership.
+ pub fn try_take<T: 'static>(&mut self) -> Option<T> {
+ let type_id = TypeId::of::<T>();
+ trace!(
+ " taking ownership from state data for type_id `{:?}`",
+ type_id
+ );
+ self
+ .data
+ .remove(&type_id)
+ .and_then(|b| b.downcast().ok())
+ .map(|b| *b)
+ }
+
+ /// Moves a value out of the `GothamState` storage and returns ownership.
+ ///
+ /// # Panics
+ ///
+ /// If a value of type `T` is not present in `GothamState`.
+ pub fn take<T: 'static>(&mut self) -> T {
+ self
+ .try_take()
+ .expect("required type is not present in GothamState container")
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::GothamState;
+
+ struct MyStruct {
+ value: i32,
+ }
+
+ struct AnotherStruct {
+ value: &'static str,
+ }
+
+ #[test]
+ fn put_borrow1() {
+ let mut state = GothamState::default();
+ state.put(MyStruct { value: 1 });
+ assert_eq!(state.borrow::<MyStruct>().value, 1);
+ }
+
+ #[test]
+ fn put_borrow2() {
+ let mut state = GothamState::default();
+ assert!(!state.has::<AnotherStruct>());
+ state.put(AnotherStruct { value: "a string" });
+ assert!(state.has::<AnotherStruct>());
+ assert!(!state.has::<MyStruct>());
+ state.put(MyStruct { value: 100 });
+ assert!(state.has::<MyStruct>());
+ assert_eq!(state.borrow::<MyStruct>().value, 100);
+ assert_eq!(state.borrow::<AnotherStruct>().value, "a string");
+ }
+
+ #[test]
+ fn try_borrow() {
+ let mut state = GothamState::default();
+ state.put(MyStruct { value: 100 });
+ assert!(state.try_borrow::<MyStruct>().is_some());
+ assert_eq!(state.try_borrow::<MyStruct>().unwrap().value, 100);
+ assert!(state.try_borrow::<AnotherStruct>().is_none());
+ }
+
+ #[test]
+ fn try_borrow_mut() {
+ let mut state = GothamState::default();
+ state.put(MyStruct { value: 100 });
+ if let Some(a) = state.try_borrow_mut::<MyStruct>() {
+ a.value += 10;
+ }
+ assert_eq!(state.borrow::<MyStruct>().value, 110);
+ }
+
+ #[test]
+ fn borrow_mut() {
+ let mut state = GothamState::default();
+ state.put(MyStruct { value: 100 });
+ {
+ let a = state.borrow_mut::<MyStruct>();
+ a.value += 10;
+ }
+ assert_eq!(state.borrow::<MyStruct>().value, 110);
+ assert!(state.try_borrow_mut::<AnotherStruct>().is_none());
+ }
+
+ #[test]
+ fn try_take() {
+ let mut state = GothamState::default();
+ state.put(MyStruct { value: 100 });
+ assert_eq!(state.try_take::<MyStruct>().unwrap().value, 100);
+ assert!(state.try_take::<MyStruct>().is_none());
+ assert!(state.try_borrow_mut::<MyStruct>().is_none());
+ assert!(state.try_borrow::<MyStruct>().is_none());
+ assert!(state.try_take::<AnotherStruct>().is_none());
+ }
+
+ #[test]
+ fn take() {
+ let mut state = GothamState::default();
+ state.put(MyStruct { value: 110 });
+ assert_eq!(state.take::<MyStruct>().value, 110);
+ assert!(state.try_take::<MyStruct>().is_none());
+ assert!(state.try_borrow_mut::<MyStruct>().is_none());
+ assert!(state.try_borrow::<MyStruct>().is_none());
+ }
+}
diff --git a/core/lib.rs b/core/lib.rs
index b27419ff5..450b7378a 100644
--- a/core/lib.rs
+++ b/core/lib.rs
@@ -8,10 +8,10 @@ extern crate lazy_static;
#[macro_use]
extern crate log;
-mod basic_state;
mod bindings;
mod errors;
mod flags;
+mod gotham_state;
mod module_specifier;
mod modules;
mod normalize_path;
@@ -24,7 +24,6 @@ mod zero_copy_buf;
pub use rusty_v8 as v8;
-pub use crate::basic_state::BasicState;
pub use crate::errors::AnyError;
pub use crate::errors::ErrBox;
pub use crate::errors::JsError;
@@ -38,12 +37,13 @@ pub use crate::modules::ModuleSource;
pub use crate::modules::ModuleSourceFuture;
pub use crate::modules::RecursiveModuleLoad;
pub use crate::normalize_path::normalize_path;
+pub use crate::ops::json_op_async;
+pub use crate::ops::json_op_sync;
pub use crate::ops::Op;
pub use crate::ops::OpAsyncFuture;
pub use crate::ops::OpFn;
pub use crate::ops::OpId;
-pub use crate::ops::OpRegistry;
-pub use crate::ops::OpRouter;
+pub use crate::ops::OpState;
pub use crate::ops::OpTable;
pub use crate::resources::ResourceTable;
pub use crate::runtime::js_check;
diff --git a/core/modules.rs b/core/modules.rs
index 3caeab7b1..57068528d 100644
--- a/core/modules.rs
+++ b/core/modules.rs
@@ -441,7 +441,6 @@ impl Modules {
mod tests {
use super::*;
use crate::js_check;
- use crate::BasicState;
use crate::JsRuntime;
use crate::StartupData;
use futures::future::FutureExt;
@@ -620,12 +619,8 @@ mod tests {
fn test_recursive_load() {
let loader = MockLoader::new();
let loads = loader.loads.clone();
- let mut runtime = JsRuntime::new_with_loader(
- loader,
- BasicState::new(),
- StartupData::None,
- false,
- );
+ let mut runtime =
+ JsRuntime::new_with_loader(loader, StartupData::None, false);
let spec = ModuleSpecifier::resolve_url("file:///a.js").unwrap();
let a_id_fut = runtime.load_module(&spec, None);
let a_id = futures::executor::block_on(a_id_fut).expect("Failed to load");
@@ -687,12 +682,8 @@ mod tests {
fn test_circular_load() {
let loader = MockLoader::new();
let loads = loader.loads.clone();
- let mut runtime = JsRuntime::new_with_loader(
- loader,
- BasicState::new(),
- StartupData::None,
- false,
- );
+ let mut runtime =
+ JsRuntime::new_with_loader(loader, StartupData::None, false);
let fut = async move {
let spec = ModuleSpecifier::resolve_url("file:///circular1.js").unwrap();
@@ -765,12 +756,8 @@ mod tests {
fn test_redirect_load() {
let loader = MockLoader::new();
let loads = loader.loads.clone();
- let mut runtime = JsRuntime::new_with_loader(
- loader,
- BasicState::new(),
- StartupData::None,
- false,
- );
+ let mut runtime =
+ JsRuntime::new_with_loader(loader, StartupData::None, false);
let fut = async move {
let spec = ModuleSpecifier::resolve_url("file:///redirect1.js").unwrap();
@@ -834,12 +821,8 @@ mod tests {
run_in_task(|mut cx| {
let loader = MockLoader::new();
let loads = loader.loads.clone();
- let mut runtime = JsRuntime::new_with_loader(
- loader,
- BasicState::new(),
- StartupData::None,
- false,
- );
+ let mut runtime =
+ JsRuntime::new_with_loader(loader, StartupData::None, false);
let spec = ModuleSpecifier::resolve_url("file:///main.js").unwrap();
let mut recursive_load = runtime.load_module(&spec, None).boxed_local();
@@ -884,12 +867,8 @@ mod tests {
fn loader_disappears_after_error() {
run_in_task(|mut cx| {
let loader = MockLoader::new();
- let mut runtime = JsRuntime::new_with_loader(
- loader,
- BasicState::new(),
- StartupData::None,
- false,
- );
+ let mut runtime =
+ JsRuntime::new_with_loader(loader, StartupData::None, false);
let spec = ModuleSpecifier::resolve_url("file:///bad_import.js").unwrap();
let mut load_fut = runtime.load_module(&spec, None).boxed_local();
let result = load_fut.poll_unpin(&mut cx);
@@ -917,12 +896,8 @@ mod tests {
fn recursive_load_main_with_code() {
let loader = MockLoader::new();
let loads = loader.loads.clone();
- let mut runtime = JsRuntime::new_with_loader(
- loader,
- BasicState::new(),
- StartupData::None,
- false,
- );
+ let mut runtime =
+ JsRuntime::new_with_loader(loader, StartupData::None, false);
// In default resolution code should be empty.
// Instead we explicitly pass in our own code.
// The behavior should be very similar to /a.js.
diff --git a/core/ops.rs b/core/ops.rs
index 838596dc0..7af4949a1 100644
--- a/core/ops.rs
+++ b/core/ops.rs
@@ -1,13 +1,13 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
+use crate::gotham_state::GothamState;
use crate::BufVec;
use crate::ErrBox;
use crate::ZeroCopyBuf;
use futures::Future;
-use futures::FutureExt;
use indexmap::IndexMap;
-use serde_json::json;
use serde_json::Value;
+use std::cell::RefCell;
use std::collections::HashMap;
use std::iter::once;
use std::ops::Deref;
@@ -16,7 +16,7 @@ use std::pin::Pin;
use std::rc::Rc;
pub type OpAsyncFuture = Pin<Box<dyn Future<Output = Box<[u8]>>>>;
-pub type OpFn<S> = dyn Fn(Rc<S>, BufVec) -> Op + 'static;
+pub type OpFn = dyn Fn(Rc<RefCell<OpState>>, BufVec) -> Op + 'static;
pub type OpId = usize;
pub enum Op {
@@ -28,119 +28,191 @@ pub enum Op {
NotFound,
}
-pub trait OpRouter {
- fn route_op(self: Rc<Self>, op_id: OpId, bufs: BufVec) -> Op;
+pub struct OpState {
+ pub resource_table: crate::ResourceTable,
+ pub op_table: OpTable,
+ pub get_error_class_fn: crate::runtime::GetErrorClassFn,
+ gotham_state: GothamState,
}
-pub trait OpRegistry: OpRouter + 'static {
- fn get_op_catalog(self: Rc<Self>) -> HashMap<String, OpId>;
-
- fn register_op<F>(&self, name: &str, op_fn: F) -> OpId
- where
- F: Fn(Rc<Self>, BufVec) -> Op + 'static;
-
- fn register_op_json_sync<F>(self: &Rc<Self>, name: &str, op_fn: F) -> OpId
- where
- F: Fn(&Self, Value, &mut [ZeroCopyBuf]) -> Result<Value, ErrBox> + 'static,
- {
- let base_op_fn = move |state: Rc<Self>, mut bufs: BufVec| -> Op {
- let result = serde_json::from_slice(&bufs[0])
- .map_err(ErrBox::from)
- .and_then(|args| op_fn(&state, args, &mut bufs[1..]));
- let buf = state.json_serialize_op_result(None, result);
- Op::Sync(buf)
- };
-
- self.register_op(name, base_op_fn)
+impl Default for OpState {
+ // TODO(ry) Only deno_core should be able to construct an OpState. But I don't
+ // know how to make default private. Maybe rename to
+ // pub(crate) fn new() -> OpState
+ fn default() -> OpState {
+ OpState {
+ resource_table: crate::ResourceTable::default(),
+ op_table: OpTable::default(),
+ get_error_class_fn: &|_| "Error",
+ gotham_state: GothamState::default(),
+ }
}
+}
- fn register_op_json_async<F, R>(self: &Rc<Self>, name: &str, op_fn: F) -> OpId
- where
- F: Fn(Rc<Self>, Value, BufVec) -> R + 'static,
- R: Future<Output = Result<Value, ErrBox>> + 'static,
- {
- let try_dispatch_op = move |state: Rc<Self>,
- bufs: BufVec|
- -> Result<Op, ErrBox> {
- let args: Value = serde_json::from_slice(&bufs[0])?;
- let promise_id = args
- .get("promiseId")
- .and_then(Value::as_u64)
- .ok_or_else(|| ErrBox::type_error("missing or invalid `promiseId`"))?;
- let bufs = bufs[1..].into();
- let fut = op_fn(state.clone(), args, bufs).map(move |result| {
- state.json_serialize_op_result(Some(promise_id), result)
- });
- Ok(Op::Async(Box::pin(fut)))
- };
-
- let base_op_fn = move |state: Rc<Self>, bufs: BufVec| -> Op {
- match try_dispatch_op(state.clone(), bufs) {
- Ok(op) => op,
- Err(err) => Op::Sync(state.json_serialize_op_result(None, Err(err))),
- }
- };
-
- self.register_op(name, base_op_fn)
- }
+impl Deref for OpState {
+ type Target = GothamState;
- fn json_serialize_op_result(
- &self,
- promise_id: Option<u64>,
- result: Result<Value, ErrBox>,
- ) -> Box<[u8]> {
- let value = match result {
- Ok(v) => json!({ "ok": v, "promiseId": promise_id }),
- Err(err) => json!({
- "promiseId": promise_id ,
- "err": {
- "className": self.get_error_class_name(&err),
- "message": err.to_string(),
- }
- }),
- };
- serde_json::to_vec(&value).unwrap().into_boxed_slice()
+ fn deref(&self) -> &Self::Target {
+ &self.gotham_state
}
+}
- fn get_error_class_name(&self, _err: &ErrBox) -> &'static str {
- "Error"
+impl DerefMut for OpState {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ &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<S>(IndexMap<String, Rc<OpFn<S>>>);
+pub struct OpTable(IndexMap<String, Rc<OpFn>>);
-impl<S: OpRegistry> OpTable<S> {
- pub fn get_op_catalog(&self) -> HashMap<String, OpId> {
- self.keys().cloned().zip(0..).collect()
+impl OpTable {
+ pub fn register_op<F>(&mut self, name: &str, op_fn: F) -> OpId
+ where
+ F: Fn(Rc<RefCell<OpState>>, BufVec) -> Op + 'static,
+ {
+ let (op_id, prev) = self.0.insert_full(name.to_owned(), Rc::new(op_fn));
+ assert!(prev.is_none());
+ op_id
}
- fn op_get_op_catalog(state: Rc<S>, _bufs: BufVec) -> Op {
- let ops = state.get_op_catalog();
- let buf = serde_json::to_vec(&ops).map(Into::into).unwrap();
- Op::Sync(buf)
+ pub fn route_op(
+ op_id: OpId,
+ state: Rc<RefCell<OpState>>,
+ bufs: BufVec,
+ ) -> Op {
+ if op_id == 0 {
+ let ops: HashMap<String, OpId> =
+ state.borrow().op_table.0.keys().cloned().zip(0..).collect();
+ let buf = serde_json::to_vec(&ops).map(Into::into).unwrap();
+ Op::Sync(buf)
+ } else {
+ 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, bufs),
+ None => Op::NotFound,
+ }
+ }
}
}
-impl<S: OpRegistry> Default for OpTable<S> {
+impl Default for OpTable {
fn default() -> Self {
- Self(
- once(("ops".to_owned(), Rc::new(Self::op_get_op_catalog) as _)).collect(),
- )
+ fn dummy(_state: Rc<RefCell<OpState>>, _bufs: BufVec) -> Op {
+ unreachable!()
+ }
+ Self(once(("ops".to_owned(), Rc::new(dummy) as _)).collect())
}
}
-impl<S> Deref for OpTable<S> {
- type Target = IndexMap<String, Rc<OpFn<S>>>;
+#[test]
+fn op_table() {
+ let state = Rc::new(RefCell::new(OpState::default()));
- fn deref(&self) -> &Self::Target {
- &self.0
+ let foo_id;
+ let bar_id;
+ {
+ let op_table = &mut state.borrow_mut().op_table;
+ foo_id = op_table.register_op("foo", |_, _| Op::Sync(b"oof!"[..].into()));
+ assert_eq!(foo_id, 1);
+ bar_id = op_table.register_op("bar", |_, _| Op::Sync(b"rab!"[..].into()));
+ assert_eq!(bar_id, 2);
}
+
+ let foo_res = OpTable::route_op(foo_id, state.clone(), Default::default());
+ assert!(matches!(foo_res, Op::Sync(buf) if &*buf == b"oof!"));
+ let bar_res = OpTable::route_op(bar_id, state.clone(), Default::default());
+ assert!(matches!(bar_res, Op::Sync(buf) if &*buf == b"rab!"));
+
+ let catalog_res = OpTable::route_op(0, state, Default::default());
+ let mut catalog_entries = match catalog_res {
+ Op::Sync(buf) => serde_json::from_slice::<HashMap<String, OpId>>(&buf)
+ .map(|map| map.into_iter().collect::<Vec<_>>())
+ .unwrap(),
+ _ => panic!("unexpected `Op` variant"),
+ };
+ 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)
+ ]
+ )
}
-impl<S> DerefMut for OpTable<S> {
- fn deref_mut(&mut self) -> &mut Self::Target {
- &mut self.0
- }
+pub fn json_op_sync<F>(op_fn: F) -> Box<OpFn>
+where
+ F: Fn(&mut OpState, Value, &mut [ZeroCopyBuf]) -> Result<Value, ErrBox>
+ + 'static,
+{
+ Box::new(move |state: Rc<RefCell<OpState>>, mut bufs: BufVec| -> Op {
+ let result = serde_json::from_slice(&bufs[0])
+ .map_err(crate::ErrBox::from)
+ .and_then(|args| op_fn(&mut state.borrow_mut(), args, &mut bufs[1..]));
+ let buf =
+ json_serialize_op_result(None, result, state.borrow().get_error_class_fn);
+ Op::Sync(buf)
+ })
+}
+
+pub fn json_op_async<F, R>(op_fn: F) -> Box<OpFn>
+where
+ F: Fn(Rc<RefCell<OpState>>, Value, BufVec) -> R + 'static,
+ R: Future<Output = Result<Value, ErrBox>> + 'static,
+{
+ let try_dispatch_op =
+ move |state: Rc<RefCell<OpState>>, bufs: BufVec| -> Result<Op, ErrBox> {
+ let args: Value = serde_json::from_slice(&bufs[0])?;
+ let promise_id = args
+ .get("promiseId")
+ .and_then(Value::as_u64)
+ .ok_or_else(|| ErrBox::type_error("missing or invalid `promiseId`"))?;
+ let bufs = bufs[1..].into();
+ use crate::futures::FutureExt;
+ let fut = op_fn(state.clone(), args, bufs).map(move |result| {
+ json_serialize_op_result(
+ Some(promise_id),
+ result,
+ state.borrow().get_error_class_fn,
+ )
+ });
+ Ok(Op::Async(Box::pin(fut)))
+ };
+
+ Box::new(move |state: Rc<RefCell<OpState>>, bufs: BufVec| -> Op {
+ match try_dispatch_op(state.clone(), bufs) {
+ Ok(op) => op,
+ Err(err) => Op::Sync(json_serialize_op_result(
+ None,
+ Err(err),
+ state.borrow().get_error_class_fn,
+ )),
+ }
+ })
+}
+
+fn json_serialize_op_result(
+ promise_id: Option<u64>,
+ result: Result<serde_json::Value, crate::ErrBox>,
+ get_error_class_fn: crate::runtime::GetErrorClassFn,
+) -> Box<[u8]> {
+ let value = match result {
+ Ok(v) => serde_json::json!({ "ok": v, "promiseId": promise_id }),
+ Err(err) => serde_json::json!({
+ "promiseId": promise_id ,
+ "err": {
+ "className": (get_error_class_fn)(&err),
+ "message": err.to_string(),
+ }
+ }),
+ };
+ serde_json::to_vec(&value).unwrap().into_boxed_slice()
}
diff --git a/core/runtime.rs b/core/runtime.rs
index 2f574b195..e6fc23084 100644
--- a/core/runtime.rs
+++ b/core/runtime.rs
@@ -19,9 +19,10 @@ use crate::modules::RecursiveModuleLoad;
use crate::ops::*;
use crate::shared_queue::SharedQueue;
use crate::shared_queue::RECOMMENDED_SIZE;
+use crate::BufVec;
use crate::ErrBox;
use crate::JsError;
-use crate::OpRouter;
+use crate::OpState;
use futures::stream::FuturesUnordered;
use futures::stream::StreamExt;
use futures::stream::StreamFuture;
@@ -94,7 +95,7 @@ impl StartupData<'_> {
type JsErrorCreateFn = dyn Fn(JsError) -> ErrBox;
-pub type GetErrorClassFn = dyn for<'e> Fn(&'e ErrBox) -> &'static str;
+pub type GetErrorClassFn = &'static dyn for<'e> Fn(&'e ErrBox) -> &'static str;
/// Objects that need to live as long as the isolate
#[derive(Default)]
@@ -137,7 +138,8 @@ pub struct JsRuntimeState {
pub(crate) pending_ops: FuturesUnordered<PendingOpFuture>,
pub(crate) pending_unref_ops: FuturesUnordered<PendingOpFuture>,
pub(crate) have_unpolled_ops: Cell<bool>,
- pub(crate) op_router: Rc<dyn OpRouter>,
+ //pub(crate) op_table: OpTable,
+ pub(crate) op_state: Rc<RefCell<OpState>>,
loader: Rc<dyn ModuleLoader>,
pub modules: Modules,
pub(crate) dyn_import_map:
@@ -219,7 +221,6 @@ pub struct HeapLimits {
pub(crate) struct IsolateOptions {
loader: Rc<dyn ModuleLoader>,
- op_router: Rc<dyn OpRouter>,
startup_script: Option<OwnedScript>,
startup_snapshot: Option<Snapshot>,
will_snapshot: bool,
@@ -229,15 +230,10 @@ pub(crate) struct IsolateOptions {
impl JsRuntime {
/// startup_data defines the snapshot or script used at startup to initialize
/// the isolate.
- pub fn new(
- op_router: Rc<dyn OpRouter>,
- startup_data: StartupData,
- will_snapshot: bool,
- ) -> Self {
+ pub fn new(startup_data: StartupData, will_snapshot: bool) -> Self {
let (startup_script, startup_snapshot) = startup_data.into_options();
let options = IsolateOptions {
loader: Rc::new(NoopModuleLoader),
- op_router,
startup_script,
startup_snapshot,
will_snapshot,
@@ -251,14 +247,12 @@ impl JsRuntime {
/// Create new isolate that can load and execute ESModules.
pub fn new_with_loader(
loader: Rc<dyn ModuleLoader>,
- op_router: Rc<dyn OpRouter>,
startup_data: StartupData,
will_snapshot: bool,
) -> Self {
let (startup_script, startup_snapshot) = startup_data.into_options();
let options = IsolateOptions {
loader,
- op_router,
startup_script,
startup_snapshot,
will_snapshot,
@@ -275,14 +269,12 @@ impl JsRuntime {
/// Make sure to use [`add_near_heap_limit_callback`](#method.add_near_heap_limit_callback)
/// to prevent v8 from crashing when reaching the upper limit.
pub fn with_heap_limits(
- op_router: Rc<dyn OpRouter>,
startup_data: StartupData,
heap_limits: HeapLimits,
) -> Self {
let (startup_script, startup_snapshot) = startup_data.into_options();
let options = IsolateOptions {
loader: Rc::new(NoopModuleLoader),
- op_router,
startup_script,
startup_snapshot,
will_snapshot: false,
@@ -347,6 +339,8 @@ impl JsRuntime {
(isolate, None)
};
+ let op_state = OpState::default();
+
isolate.set_slot(Rc::new(RefCell::new(JsRuntimeState {
global_context: Some(global_context),
pending_promise_exceptions: HashMap::new(),
@@ -357,8 +351,8 @@ impl JsRuntime {
shared: SharedQueue::new(RECOMMENDED_SIZE),
pending_ops: FuturesUnordered::new(),
pending_unref_ops: FuturesUnordered::new(),
+ op_state: Rc::new(RefCell::new(op_state)),
have_unpolled_ops: Cell::new(false),
- op_router: options.op_router,
modules: Modules::new(),
loader: options.loader,
dyn_import_map: HashMap::new(),
@@ -406,6 +400,12 @@ impl JsRuntime {
}
}
+ pub fn op_state(&mut self) -> Rc<RefCell<OpState>> {
+ let state_rc = Self::state(self);
+ let state = state_rc.borrow();
+ state.op_state.clone()
+ }
+
/// Executes traditional JavaScript code (traditional = not ES modules)
///
/// ErrBox can be downcast to a type that exposes additional information about
@@ -477,6 +477,18 @@ impl JsRuntime {
snapshot
}
+ pub fn register_op<F>(&mut self, name: &str, op_fn: F) -> OpId
+ where
+ F: Fn(Rc<RefCell<OpState>>, BufVec) -> Op + 'static,
+ {
+ Self::state(self)
+ .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.
///
@@ -1283,8 +1295,6 @@ impl JsRuntime {
pub mod tests {
use super::*;
use crate::modules::ModuleSourceFuture;
- use crate::ops::*;
- use crate::BasicState;
use crate::BufVec;
use futures::future::lazy;
use futures::FutureExt;
@@ -1328,89 +1338,89 @@ pub mod tests {
OverflowResAsync,
}
- struct TestOpRouter {
+ struct TestState {
mode: Mode,
dispatch_count: Arc<AtomicUsize>,
}
- impl OpRouter for TestOpRouter {
- fn route_op(self: Rc<Self>, op_id: OpId, bufs: BufVec) -> Op {
- if op_id != 1 {
- return Op::NotFound;
+ fn dispatch(op_state: Rc<RefCell<OpState>>, bufs: BufVec) -> Op {
+ let op_state_ = op_state.borrow();
+ let test_state = op_state_.borrow::<TestState>();
+ test_state.dispatch_count.fetch_add(1, Ordering::Relaxed);
+ match test_state.mode {
+ Mode::Async => {
+ assert_eq!(bufs.len(), 1);
+ assert_eq!(bufs[0].len(), 1);
+ assert_eq!(bufs[0][0], 42);
+ let buf = vec![43u8].into_boxed_slice();
+ Op::Async(futures::future::ready(buf).boxed())
}
- self.dispatch_count.fetch_add(1, Ordering::Relaxed);
- match self.mode {
- Mode::Async => {
- assert_eq!(bufs.len(), 1);
- assert_eq!(bufs[0].len(), 1);
- assert_eq!(bufs[0][0], 42);
- let buf = vec![43u8].into_boxed_slice();
- Op::Async(futures::future::ready(buf).boxed())
- }
- Mode::AsyncUnref => {
- assert_eq!(bufs.len(), 1);
- assert_eq!(bufs[0].len(), 1);
- assert_eq!(bufs[0][0], 42);
- let fut = async {
- // This future never finish.
- futures::future::pending::<()>().await;
- vec![43u8].into_boxed_slice()
- };
- Op::AsyncUnref(fut.boxed())
- }
- Mode::AsyncZeroCopy(count) => {
- assert_eq!(bufs.len(), count as usize);
- bufs.iter().enumerate().for_each(|(idx, buf)| {
- assert_eq!(buf.len(), 1);
- assert_eq!(idx, buf[0] as usize);
- });
-
- let buf = vec![43u8].into_boxed_slice();
- Op::Async(futures::future::ready(buf).boxed())
- }
- Mode::OverflowReqSync => {
- assert_eq!(bufs.len(), 1);
- assert_eq!(bufs[0].len(), 100 * 1024 * 1024);
- let buf = vec![43u8].into_boxed_slice();
- Op::Sync(buf)
- }
- Mode::OverflowResSync => {
- assert_eq!(bufs.len(), 1);
- assert_eq!(bufs[0].len(), 1);
- assert_eq!(bufs[0][0], 42);
- let mut vec = Vec::<u8>::new();
- vec.resize(100 * 1024 * 1024, 0);
- vec[0] = 99;
- let buf = vec.into_boxed_slice();
- Op::Sync(buf)
- }
- Mode::OverflowReqAsync => {
- assert_eq!(bufs.len(), 1);
- assert_eq!(bufs[0].len(), 100 * 1024 * 1024);
- let buf = vec![43u8].into_boxed_slice();
- Op::Async(futures::future::ready(buf).boxed())
- }
- Mode::OverflowResAsync => {
- assert_eq!(bufs.len(), 1);
- assert_eq!(bufs[0].len(), 1);
- assert_eq!(bufs[0][0], 42);
- let mut vec = Vec::<u8>::new();
- vec.resize(100 * 1024 * 1024, 0);
- vec[0] = 4;
- let buf = vec.into_boxed_slice();
- Op::Async(futures::future::ready(buf).boxed())
- }
+ Mode::AsyncUnref => {
+ assert_eq!(bufs.len(), 1);
+ assert_eq!(bufs[0].len(), 1);
+ assert_eq!(bufs[0][0], 42);
+ let fut = async {
+ // This future never finish.
+ futures::future::pending::<()>().await;
+ vec![43u8].into_boxed_slice()
+ };
+ Op::AsyncUnref(fut.boxed())
+ }
+ Mode::AsyncZeroCopy(count) => {
+ assert_eq!(bufs.len(), count as usize);
+ bufs.iter().enumerate().for_each(|(idx, buf)| {
+ assert_eq!(buf.len(), 1);
+ assert_eq!(idx, buf[0] as usize);
+ });
+
+ let buf = vec![43u8].into_boxed_slice();
+ Op::Async(futures::future::ready(buf).boxed())
+ }
+ Mode::OverflowReqSync => {
+ assert_eq!(bufs.len(), 1);
+ assert_eq!(bufs[0].len(), 100 * 1024 * 1024);
+ let buf = vec![43u8].into_boxed_slice();
+ Op::Sync(buf)
+ }
+ Mode::OverflowResSync => {
+ assert_eq!(bufs.len(), 1);
+ assert_eq!(bufs[0].len(), 1);
+ assert_eq!(bufs[0][0], 42);
+ let mut vec = Vec::<u8>::new();
+ vec.resize(100 * 1024 * 1024, 0);
+ vec[0] = 99;
+ let buf = vec.into_boxed_slice();
+ Op::Sync(buf)
+ }
+ Mode::OverflowReqAsync => {
+ assert_eq!(bufs.len(), 1);
+ assert_eq!(bufs[0].len(), 100 * 1024 * 1024);
+ let buf = vec![43u8].into_boxed_slice();
+ Op::Async(futures::future::ready(buf).boxed())
+ }
+ Mode::OverflowResAsync => {
+ assert_eq!(bufs.len(), 1);
+ assert_eq!(bufs[0].len(), 1);
+ assert_eq!(bufs[0][0], 42);
+ let mut vec = Vec::<u8>::new();
+ vec.resize(100 * 1024 * 1024, 0);
+ vec[0] = 4;
+ let buf = vec.into_boxed_slice();
+ Op::Async(futures::future::ready(buf).boxed())
}
}
}
fn setup(mode: Mode) -> (JsRuntime, Arc<AtomicUsize>) {
let dispatch_count = Arc::new(AtomicUsize::new(0));
- let test_state = Rc::new(TestOpRouter {
+ let mut runtime = JsRuntime::new(StartupData::None, false);
+ let op_state = runtime.op_state();
+ op_state.borrow_mut().put(TestState {
mode,
dispatch_count: dispatch_count.clone(),
});
- let mut runtime = JsRuntime::new(test_state, StartupData::None, false);
+
+ runtime.register_op("test", dispatch);
js_check(runtime.execute(
"setup.js",
@@ -1774,8 +1784,7 @@ pub mod tests {
#[test]
fn syntax_error() {
- let mut runtime =
- JsRuntime::new(BasicState::new(), StartupData::None, false);
+ let mut runtime = JsRuntime::new(StartupData::None, false);
let src = "hocuspocus(";
let r = runtime.execute("i.js", src);
let e = r.unwrap_err();
@@ -1800,29 +1809,27 @@ pub mod tests {
#[test]
fn will_snapshot() {
let snapshot = {
- let mut runtime =
- JsRuntime::new(BasicState::new(), StartupData::None, true);
+ let mut runtime = JsRuntime::new(StartupData::None, true);
js_check(runtime.execute("a.js", "a = 1 + 2"));
runtime.snapshot()
};
let startup_data = StartupData::Snapshot(Snapshot::JustCreated(snapshot));
- let mut runtime2 = JsRuntime::new(BasicState::new(), startup_data, false);
+ let mut runtime2 = JsRuntime::new(startup_data, false);
js_check(runtime2.execute("check.js", "if (a != 3) throw Error('x')"));
}
#[test]
fn test_from_boxed_snapshot() {
let snapshot = {
- let mut runtime =
- JsRuntime::new(BasicState::new(), StartupData::None, true);
+ let mut runtime = JsRuntime::new(StartupData::None, true);
js_check(runtime.execute("a.js", "a = 1 + 2"));
let snap: &[u8] = &*runtime.snapshot();
Vec::from(snap).into_boxed_slice()
};
let startup_data = StartupData::Snapshot(Snapshot::Boxed(snapshot));
- let mut runtime2 = JsRuntime::new(BasicState::new(), startup_data, false);
+ let mut runtime2 = JsRuntime::new(startup_data, false);
js_check(runtime2.execute("check.js", "if (a != 3) throw Error('x')"));
}
@@ -1832,11 +1839,8 @@ pub mod tests {
initial: 0,
max: 20 * 1024, // 20 kB
};
- let mut runtime = JsRuntime::with_heap_limits(
- BasicState::new(),
- StartupData::None,
- heap_limits,
- );
+ let mut runtime =
+ JsRuntime::with_heap_limits(StartupData::None, heap_limits);
let cb_handle = runtime.thread_safe_handle();
let callback_invoke_count = Rc::new(AtomicUsize::default());
@@ -1864,8 +1868,7 @@ pub mod tests {
#[test]
fn test_heap_limit_cb_remove() {
- let mut runtime =
- JsRuntime::new(BasicState::new(), StartupData::None, false);
+ let mut runtime = JsRuntime::new(StartupData::None, false);
runtime.add_near_heap_limit_callback(|current_limit, _initial_limit| {
current_limit * 2
@@ -1880,11 +1883,8 @@ pub mod tests {
initial: 0,
max: 20 * 1024, // 20 kB
};
- let mut runtime = JsRuntime::with_heap_limits(
- BasicState::new(),
- StartupData::None,
- heap_limits,
- );
+ let mut runtime =
+ JsRuntime::with_heap_limits(StartupData::None, heap_limits);
let cb_handle = runtime.thread_safe_handle();
let callback_invoke_count_first = Rc::new(AtomicUsize::default());
@@ -1952,13 +1952,12 @@ pub mod tests {
}
let loader = Rc::new(ModsLoader::default());
- let state = BasicState::new();
let resolve_count = loader.count.clone();
let dispatch_count = Arc::new(AtomicUsize::new(0));
let dispatch_count_ = dispatch_count.clone();
- let dispatcher = move |_state: Rc<BasicState>, bufs: BufVec| -> Op {
+ let dispatcher = move |_state: Rc<RefCell<OpState>>, bufs: BufVec| -> Op {
dispatch_count_.fetch_add(1, Ordering::Relaxed);
assert_eq!(bufs.len(), 1);
assert_eq!(bufs[0].len(), 1);
@@ -1966,10 +1965,10 @@ pub mod tests {
let buf = [43u8, 0, 0, 0][..].into();
Op::Async(futures::future::ready(buf).boxed())
};
- state.register_op("test", dispatcher);
let mut runtime =
- JsRuntime::new_with_loader(loader, state, StartupData::None, false);
+ JsRuntime::new_with_loader(loader, StartupData::None, false);
+ runtime.register_op("test", dispatcher);
js_check(runtime.execute(
"setup.js",
@@ -2063,12 +2062,8 @@ pub mod tests {
run_in_task(|cx| {
let loader = Rc::new(DynImportErrLoader::default());
let count = loader.count.clone();
- let mut runtime = JsRuntime::new_with_loader(
- loader,
- BasicState::new(),
- StartupData::None,
- false,
- );
+ let mut runtime =
+ JsRuntime::new_with_loader(loader, StartupData::None, false);
js_check(runtime.execute(
"file:///dyn_import2.js",
@@ -2145,12 +2140,8 @@ pub mod tests {
let prepare_load_count = loader.prepare_load_count.clone();
let resolve_count = loader.resolve_count.clone();
let load_count = loader.load_count.clone();
- let mut runtime = JsRuntime::new_with_loader(
- loader,
- BasicState::new(),
- StartupData::None,
- false,
- );
+ let mut runtime =
+ JsRuntime::new_with_loader(loader, StartupData::None, false);
// Dynamically import mod_b
js_check(runtime.execute(
@@ -2190,12 +2181,8 @@ pub mod tests {
run_in_task(|cx| {
let loader = Rc::new(DynImportOkLoader::default());
let prepare_load_count = loader.prepare_load_count.clone();
- let mut runtime = JsRuntime::new_with_loader(
- loader,
- BasicState::new(),
- StartupData::None,
- false,
- );
+ let mut runtime =
+ JsRuntime::new_with_loader(loader, StartupData::None, false);
js_check(runtime.execute(
"file:///dyn_import3.js",
r#"
@@ -2246,12 +2233,8 @@ pub mod tests {
}
let loader = std::rc::Rc::new(ModsLoader::default());
- let mut runtime = JsRuntime::new_with_loader(
- loader,
- BasicState::new(),
- StartupData::None,
- true,
- );
+ let mut runtime =
+ JsRuntime::new_with_loader(loader, StartupData::None, true);
let specifier = ModuleSpecifier::resolve_url("file:///main.js").unwrap();
let source_code = "Deno.core.print('hello\\n')".to_string();