summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/ops.rs48
-rw-r--r--core/resources.rs34
-rw-r--r--core/runtime.rs15
3 files changed, 96 insertions, 1 deletions
diff --git a/core/ops.rs b/core/ops.rs
index 3351b6a5b..ed74ce873 100644
--- a/core/ops.rs
+++ b/core/ops.rs
@@ -31,6 +31,7 @@ pub enum Op {
NotFound,
}
+/// Maintains the resources and ops inside a JS runtime.
pub struct OpState {
pub resource_table: crate::ResourceTable,
pub op_table: OpTable,
@@ -151,6 +152,29 @@ fn op_table() {
)
}
+/// 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.
+/// * `Value`: the JSON 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.
+///
+/// When registering an op like this...
+/// ```ignore
+/// let mut runtime = JsRuntime::new(...);
+/// runtime.register_op("hello", deno_core::json_op_sync(Self::hello_op));
+/// ```
+///
+/// ...it can be invoked from JS using the provided name, for example:
+/// ```js
+/// Deno.core.ops();
+/// let result = Deno.core.jsonOpSync("function_name", args);
+/// ```
+///
+/// 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>
where
F: Fn(&mut OpState, Value, &mut [ZeroCopyBuf]) -> Result<Value, AnyError>
@@ -166,6 +190,30 @@ where
})
}
+/// Creates an op that passes data asynchronously using JSON.
+///
+/// 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.
+/// * `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
+/// returned to JavaScript.
+///
+/// When registering an op like this...
+/// ```ignore
+/// let mut runtime = JsRuntime::new(...);
+/// runtime.register_op("hello", deno_core::json_op_async(Self::hello_op));
+/// ```
+///
+/// ...it can be invoked from JS using the provided name, for example:
+/// ```js
+/// Deno.core.ops();
+/// let future = Deno.core.jsonOpAsync("function_name", args);
+/// ```
+///
+/// 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>
where
F: Fn(Rc<RefCell<OpState>>, Value, BufVec) -> R + 'static,
diff --git a/core/resources.rs b/core/resources.rs
index 0a159425c..25ea95f41 100644
--- a/core/resources.rs
+++ b/core/resources.rs
@@ -10,13 +10,21 @@ use std::any::Any;
use std::collections::HashMap;
/// ResourceId is Deno's version of a file descriptor. ResourceId is also referred
-/// to as rid in the code base.
+/// to as `rid` in the code base.
pub type ResourceId = u32;
/// These store Deno's file descriptors. These are not necessarily the operating
/// system ones.
type ResourceMap = HashMap<ResourceId, (String, Box<dyn Any>)>;
+/// Map-like data structure storing Deno's resources (equivalent to file descriptors).
+///
+/// Provides basic methods for element access. A resource can be of any type.
+/// Different types of resources can be stored in the same map, and provided
+/// with a name for description.
+///
+/// Each resource is identified through a _resource ID (rid)_, which acts as
+/// the key in the map.
#[derive(Default)]
pub struct ResourceTable {
map: ResourceMap,
@@ -24,15 +32,22 @@ pub struct ResourceTable {
}
impl ResourceTable {
+ /// Checks if the given resource ID is contained.
pub fn has(&self, rid: ResourceId) -> bool {
self.map.contains_key(&rid)
}
+ /// Returns a shared reference to a resource.
+ ///
+ /// Returns `None`, if `rid` is not stored or has a type different from `T`.
pub fn get<T: Any>(&self, rid: ResourceId) -> Option<&T> {
let (_, resource) = self.map.get(&rid)?;
resource.downcast_ref::<T>()
}
+ /// Returns a mutable reference to a resource.
+ ///
+ /// Returns `None`, if `rid` is not stored or has a type different from `T`.
pub fn get_mut<T: Any>(&mut self, rid: ResourceId) -> Option<&mut T> {
let (_, resource) = self.map.get_mut(&rid)?;
resource.downcast_mut::<T>()
@@ -45,6 +60,12 @@ impl ResourceTable {
next_rid as ResourceId
}
+ /// Inserts a resource, taking ownership of it.
+ ///
+ /// The resource type is erased at runtime and must be statically known
+ /// when retrieving it through `get()`.
+ ///
+ /// Returns a unique resource ID, which acts as a key for this resource.
pub fn add(&mut self, name: &str, resource: Box<dyn Any>) -> ResourceId {
let rid = self.next_rid();
let r = self.map.insert(rid, (name.to_string(), resource));
@@ -52,6 +73,10 @@ impl ResourceTable {
rid
}
+ /// Returns a map of resource IDs to names.
+ ///
+ /// The name is the one specified during `add()`. To access resources themselves,
+ /// use the `get()` or `get_mut()` functions.
pub fn entries(&self) -> HashMap<ResourceId, String> {
self
.map
@@ -66,6 +91,13 @@ impl ResourceTable {
self.map.remove(&rid).map(|(_name, _resource)| ())
}
+ /// Removes the resource identified by `rid` and returns it.
+ ///
+ /// When the provided `rid` is stored, the associated resource will be removed.
+ /// Otherwise, nothing happens and `None` is returned.
+ ///
+ /// If the type `T` matches the resource's type, the resource will be returned.
+ /// If the type mismatches, `None` is returned, but the resource is still removed.
pub fn remove<T: Any>(&mut self, rid: ResourceId) -> Option<Box<T>> {
if let Some((_name, resource)) = self.map.remove(&rid) {
let res = match resource.downcast::<T>() {
diff --git a/core/runtime.rs b/core/runtime.rs
index 0fa465bf2..9766f71fa 100644
--- a/core/runtime.rs
+++ b/core/runtime.rs
@@ -191,6 +191,7 @@ pub struct RuntimeOptions {
}
impl JsRuntime {
+ /// Only constructor, configuration is done through `options`.
pub fn new(mut options: RuntimeOptions) -> Self {
static DENO_INIT: Once = Once::new();
DENO_INIT.call_once(|| {
@@ -320,6 +321,8 @@ impl JsRuntime {
}
}
+ /// Returns the runtime's op state, which can be used to maintain ops
+ /// and access resources between op calls.
pub fn op_state(&mut self) -> Rc<RefCell<OpState>> {
let state_rc = Self::state(self.v8_isolate());
let state = state_rc.borrow();
@@ -328,6 +331,9 @@ impl JsRuntime {
/// Executes traditional JavaScript code (traditional = not ES modules)
///
+ /// The execution takes place on the current global context, so it is possible
+ /// to maintain local JS state and invoke this method multiple times.
+ ///
/// `AnyError` can be downcast to a type that exposes additional information
/// about the V8 exception. By default this type is `JsError`, however it may
/// be a different type if `RuntimeOptions::js_error_create_fn` has been set.
@@ -391,6 +397,15 @@ 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`:
+ /// * [json_op_sync()](fn.json_op_sync.html)
+ /// * [json_op_async()](fn.json_op_async.html)
pub fn register_op<F>(&mut self, name: &str, op_fn: F) -> OpId
where
F: Fn(Rc<RefCell<OpState>>, BufVec) -> Op + 'static,