summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/core.js13
-rw-r--r--core/examples/hello_world.rs22
-rw-r--r--core/examples/http_bench_json_ops.js2
-rw-r--r--core/examples/http_bench_json_ops.rs74
-rw-r--r--core/lib.deno_core.d.ts4
-rw-r--r--core/ops.rs40
6 files changed, 63 insertions, 92 deletions
diff --git a/core/core.js b/core/core.js
index 57eb8b07e..a96ce81d7 100644
--- a/core/core.js
+++ b/core/core.js
@@ -213,12 +213,13 @@ SharedQueue Binary Layout
throw new ErrorClass(res.err.message);
}
- async function jsonOpAsync(opName, args = {}, ...zeroCopy) {
+ async function jsonOpAsync(opName, args = null, ...zeroCopy) {
setAsyncHandler(opsCache[opName], jsonOpAsyncHandler);
- args.promiseId = nextPromiseId++;
- const argsBuf = encodeJson(args);
- dispatch(opName, argsBuf, ...zeroCopy);
+ const promiseId = nextPromiseId++;
+ const reqBuf = core.encode("\0".repeat(8) + JSON.stringify(args));
+ new DataView(reqBuf.buffer).setBigUint64(0, BigInt(promiseId));
+ dispatch(opName, reqBuf, ...zeroCopy);
let resolve, reject;
const promise = new Promise((resolve_, reject_) => {
resolve = resolve_;
@@ -226,11 +227,11 @@ SharedQueue Binary Layout
});
promise.resolve = resolve;
promise.reject = reject;
- promiseTable[args.promiseId] = promise;
+ promiseTable[promiseId] = promise;
return processResponse(await promise);
}
- function jsonOpSync(opName, args = {}, ...zeroCopy) {
+ function jsonOpSync(opName, args = null, ...zeroCopy) {
const argsBuf = encodeJson(args);
const res = dispatch(opName, argsBuf, ...zeroCopy);
return processResponse(decodeJson(res));
diff --git a/core/examples/hello_world.rs b/core/examples/hello_world.rs
index 1f696a817..c46fc1d98 100644
--- a/core/examples/hello_world.rs
+++ b/core/examples/hello_world.rs
@@ -50,27 +50,13 @@ fn main() {
// The json_op_sync function automatically deserializes
// the first ZeroCopyBuf and serializes the return value
// to reduce boilerplate
- json_op_sync(|_state, json, zero_copy| {
- // We check that we only got the JSON value,
- // and that it's of the right type.
+ json_op_sync(|_state, json: Vec<f64>, zero_copy| {
+ // We check that we only got the JSON value.
if !zero_copy.is_empty() {
Err(anyhow!("Expected exactly one argument"))
- } else if !json.is_array() {
- Err(anyhow!("Argument is not of type array"))
- } else if !json
- .as_array()
- .unwrap()
- .iter()
- .all(|value| value.is_number())
- {
- Err(anyhow!("Argument is not array of numbers"))
} else {
- // And if everything checks out we do our actual task
- let sum = json
- .as_array()
- .unwrap()
- .iter()
- .fold(0.0, |a, v| a + v.as_f64().unwrap());
+ // And if we did, do our actual task
+ let sum = json.iter().fold(0.0, |a, v| a + v);
// Finally we return a JSON value
Ok(Value::from(sum))
diff --git a/core/examples/http_bench_json_ops.js b/core/examples/http_bench_json_ops.js
index 80c5a6115..071df100f 100644
--- a/core/examples/http_bench_json_ops.js
+++ b/core/examples/http_bench_json_ops.js
@@ -11,7 +11,7 @@ const responseBuf = new Uint8Array(
/** Listens on 0.0.0.0:4500, returns rid. */
function listen() {
- const { rid } = Deno.core.jsonOpSync("listen", {});
+ const { rid } = Deno.core.jsonOpSync("listen");
return rid;
}
diff --git a/core/examples/http_bench_json_ops.rs b/core/examples/http_bench_json_ops.rs
index 4fd25d6b8..c24175747 100644
--- a/core/examples/http_bench_json_ops.rs
+++ b/core/examples/http_bench_json_ops.rs
@@ -14,10 +14,11 @@ use deno_core::OpState;
use deno_core::RcRef;
use deno_core::Resource;
use deno_core::ZeroCopyBuf;
+use serde::Deserialize;
+use serde::Serialize;
use serde_json::Value;
use std::cell::RefCell;
use std::convert::TryFrom;
-use std::convert::TryInto;
use std::env;
use std::io::Error;
use std::net::SocketAddr;
@@ -124,83 +125,67 @@ fn create_js_runtime() -> JsRuntime {
runtime
}
+#[derive(Deserialize, Serialize)]
+struct ResourceId {
+ rid: u32,
+}
+
fn op_listen(
state: &mut OpState,
- _args: Value,
+ _args: (),
_bufs: &mut [ZeroCopyBuf],
-) -> Result<Value, AnyError> {
+) -> Result<ResourceId, AnyError> {
debug!("listen");
let addr = "127.0.0.1:4544".parse::<SocketAddr>().unwrap();
let std_listener = std::net::TcpListener::bind(&addr)?;
std_listener.set_nonblocking(true)?;
let listener = TcpListener::try_from(std_listener)?;
let rid = state.resource_table.add(listener);
- Ok(serde_json::json!({ "rid": rid }))
+ Ok(ResourceId { rid })
}
fn op_close(
state: &mut OpState,
- args: Value,
+ args: ResourceId,
_buf: &mut [ZeroCopyBuf],
-) -> Result<Value, AnyError> {
- let rid: u32 = args
- .get("rid")
- .unwrap()
- .as_u64()
- .unwrap()
- .try_into()
- .unwrap();
- debug!("close rid={}", rid);
+) -> Result<(), AnyError> {
+ debug!("close rid={}", args.rid);
state
.resource_table
- .close(rid)
- .map(|_| serde_json::json!(()))
+ .close(args.rid)
+ .map(|_| ())
.ok_or_else(bad_resource_id)
}
async fn op_accept(
state: Rc<RefCell<OpState>>,
- args: Value,
+ args: ResourceId,
_bufs: BufVec,
-) -> Result<Value, AnyError> {
- let rid: u32 = args
- .get("rid")
- .unwrap()
- .as_u64()
- .unwrap()
- .try_into()
- .unwrap();
- debug!("accept rid={}", rid);
+) -> Result<ResourceId, AnyError> {
+ debug!("accept rid={}", args.rid);
let listener = state
.borrow()
.resource_table
- .get::<TcpListener>(rid)
+ .get::<TcpListener>(args.rid)
.ok_or_else(bad_resource_id)?;
let stream = listener.accept().await?;
let rid = state.borrow_mut().resource_table.add(stream);
- Ok(serde_json::json!({ "rid": rid }))
+ Ok(ResourceId { rid })
}
async fn op_read(
state: Rc<RefCell<OpState>>,
- args: Value,
+ args: ResourceId,
mut bufs: BufVec,
) -> Result<Value, AnyError> {
assert_eq!(bufs.len(), 1, "Invalid number of arguments");
- let rid: u32 = args
- .get("rid")
- .unwrap()
- .as_u64()
- .unwrap()
- .try_into()
- .unwrap();
- debug!("read rid={}", rid);
+ debug!("read rid={}", args.rid);
let stream = state
.borrow()
.resource_table
- .get::<TcpStream>(rid)
+ .get::<TcpStream>(args.rid)
.ok_or_else(bad_resource_id)?;
let nread = stream.read(&mut bufs[0]).await?;
Ok(serde_json::json!({ "nread": nread }))
@@ -208,23 +193,16 @@ async fn op_read(
async fn op_write(
state: Rc<RefCell<OpState>>,
- args: Value,
+ args: ResourceId,
bufs: BufVec,
) -> Result<Value, AnyError> {
assert_eq!(bufs.len(), 1, "Invalid number of arguments");
- let rid: u32 = args
- .get("rid")
- .unwrap()
- .as_u64()
- .unwrap()
- .try_into()
- .unwrap();
- debug!("write rid={}", rid);
+ debug!("write rid={}", args.rid);
let stream = state
.borrow()
.resource_table
- .get::<TcpStream>(rid)
+ .get::<TcpStream>(args.rid)
.ok_or_else(bad_resource_id)?;
let nwritten = stream.write(&bufs[0]).await?;
Ok(serde_json::json!({ "nwritten": nwritten }))
diff --git a/core/lib.deno_core.d.ts b/core/lib.deno_core.d.ts
index f78c6fec2..1efb92dc6 100644
--- a/core/lib.deno_core.d.ts
+++ b/core/lib.deno_core.d.ts
@@ -10,14 +10,14 @@ declare namespace Deno {
/** Send a JSON op to Rust, and synchronously receive the result. */
function jsonOpSync(
opName: string,
- args: any,
+ args?: any,
...zeroCopy: Uint8Array[]
): any;
/** Send a JSON op to Rust, and asynchronously receive the result. */
function jsonOpAsync(
opName: string,
- args: any,
+ args?: any,
...zeroCopy: Uint8Array[]
): Promise<any>;
diff --git a/core/ops.rs b/core/ops.rs
index cedc3a6ea..eceab7feb 100644
--- a/core/ops.rs
+++ b/core/ops.rs
@@ -10,10 +10,13 @@ use crate::BufVec;
use crate::ZeroCopyBuf;
use futures::Future;
use indexmap::IndexMap;
+use serde::de::DeserializeOwned;
+use serde::Serialize;
use serde_json::json;
use serde_json::Value;
use std::cell::RefCell;
use std::collections::HashMap;
+use std::convert::TryInto;
use std::iter::once;
use std::ops::Deref;
use std::ops::DerefMut;
@@ -118,10 +121,10 @@ impl Default for OpTable {
///
/// 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.
-/// * `Value`: the JSON value that is passed to the Rust function.
+/// * `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 JSON value, which is directly returned to JavaScript.
+/// `op_fn` returns a serializable value, which is directly returned to JavaScript.
///
/// When registering an op like this...
/// ```ignore
@@ -137,10 +140,11 @@ impl Default for OpTable {
///
/// The `Deno.core.ops()` statement is needed once before any op calls, for initialization.
/// A more complete example is available in the examples directory.
-pub fn json_op_sync<F>(op_fn: F) -> Box<OpFn>
+pub fn json_op_sync<F, V, R>(op_fn: F) -> Box<OpFn>
where
- F: Fn(&mut OpState, Value, &mut [ZeroCopyBuf]) -> Result<Value, AnyError>
- + 'static,
+ F: Fn(&mut OpState, V, &mut [ZeroCopyBuf]) -> Result<R, AnyError> + 'static,
+ V: DeserializeOwned,
+ R: Serialize,
{
Box::new(move |state: Rc<RefCell<OpState>>, mut bufs: BufVec| -> Op {
let result = serde_json::from_slice(&bufs[0])
@@ -156,10 +160,10 @@ where
///
/// 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.
-/// * `Value`: the JSON value that is passed to the Rust function.
+/// * `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 JSON value. This value will be asynchronously
+/// `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...
@@ -176,18 +180,20 @@ where
///
/// The `Deno.core.ops()` statement is needed once before any op calls, for initialization.
/// A more complete example is available in the examples directory.
-pub fn json_op_async<F, R>(op_fn: F) -> Box<OpFn>
+pub fn json_op_async<F, V, R, RV>(op_fn: F) -> Box<OpFn>
where
- F: Fn(Rc<RefCell<OpState>>, Value, BufVec) -> R + 'static,
- R: Future<Output = Result<Value, AnyError>> + 'static,
+ F: Fn(Rc<RefCell<OpState>>, V, BufVec) -> R + 'static,
+ V: DeserializeOwned,
+ R: Future<Output = Result<RV, AnyError>> + 'static,
+ RV: Serialize,
{
let try_dispatch_op =
move |state: Rc<RefCell<OpState>>, bufs: BufVec| -> Result<Op, AnyError> {
- let args: Value = serde_json::from_slice(&bufs[0])?;
- let promise_id = args
- .get("promiseId")
- .and_then(Value::as_u64)
+ let promise_id = bufs[0]
+ .get(0..8)
+ .map(|b| u64::from_be_bytes(b.try_into().unwrap()))
.ok_or_else(|| type_error("missing or invalid `promiseId`"))?;
+ let args = serde_json::from_slice(&bufs[0][8..])?;
let bufs = bufs[1..].into();
use crate::futures::FutureExt;
let fut = op_fn(state.clone(), args, bufs).map(move |result| {
@@ -205,16 +211,16 @@ where
Ok(op) => op,
Err(err) => Op::Sync(json_serialize_op_result(
None,
- Err(err),
+ Err::<(), AnyError>(err),
state.borrow().get_error_class_fn,
)),
}
})
}
-fn json_serialize_op_result(
+fn json_serialize_op_result<R: Serialize>(
promise_id: Option<u64>,
- result: Result<serde_json::Value, AnyError>,
+ result: Result<R, AnyError>,
get_error_class_fn: crate::runtime::GetErrorClassFn,
) -> Box<[u8]> {
let value = match result {