diff options
Diffstat (limited to 'core')
-rw-r--r-- | core/ops.rs | 48 | ||||
-rw-r--r-- | core/resources.rs | 34 | ||||
-rw-r--r-- | core/runtime.rs | 15 |
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, |