summaryrefslogtreecommitdiff
path: root/core/resources2.rs
diff options
context:
space:
mode:
authorBert Belder <bertbelder@gmail.com>2020-11-25 00:38:23 +0100
committerBert Belder <bertbelder@gmail.com>2020-11-25 01:15:14 +0100
commit8d12653738066facfc228b1d0d9e31b76c6d9de0 (patch)
treee45c90cc79607fd5c8a29d0231f9cc43353399ac /core/resources2.rs
parent605874ee98b52f5de7d1d1284507d5a9cb9eea9d (diff)
core: implement 'AsyncRefCell' and 'ResourceTable2' (#8273)
Diffstat (limited to 'core/resources2.rs')
-rw-r--r--core/resources2.rs140
1 files changed, 140 insertions, 0 deletions
diff --git a/core/resources2.rs b/core/resources2.rs
new file mode 100644
index 000000000..52bd4f3e7
--- /dev/null
+++ b/core/resources2.rs
@@ -0,0 +1,140 @@
+// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
+
+// Think of Resources as File Descriptors. They are integers that are allocated
+// by the privileged side of Deno which refer to various rust objects that need
+// to be persisted between various ops. For example, network sockets are
+// resources. Resources may or may not correspond to a real operating system
+// file descriptor (hence the different name).
+
+use std::any::type_name;
+use std::any::Any;
+use std::any::TypeId;
+use std::borrow::Cow;
+use std::collections::HashMap;
+use std::iter::Iterator;
+use std::rc::Rc;
+
+/// All objects that can be store in the resource table should implement the
+/// `Resource` trait.
+pub trait Resource: Any + 'static {
+ /// Returns a string representation of the resource which is made available
+ /// to JavaScript code through `op_resources`. The default implementation
+ /// returns the Rust type name, but specific resource types may override this
+ /// trait method.
+ fn name(&self) -> Cow<str> {
+ type_name::<Self>().into()
+ }
+}
+
+impl dyn Resource {
+ #[inline(always)]
+ fn is<T: Resource>(&self) -> bool {
+ self.type_id() == TypeId::of::<T>()
+ }
+
+ #[inline(always)]
+ fn downcast_rc<'a, T: Resource>(self: &'a Rc<Self>) -> Option<&'a Rc<T>> {
+ if self.is::<T>() {
+ let ptr = self as *const Rc<_> as *const Rc<T>;
+ Some(unsafe { &*ptr })
+ } else {
+ None
+ }
+ }
+}
+
+/// A `ResourceId` is an integer value referencing a resource. It could be
+/// considered to be the Deno equivalent of a `file descriptor` in POSIX like
+/// operating systems. Elsewhere in the code base it is commonly abbreviated
+/// to `rid`.
+// TODO: use `u64` instead?
+pub type ResourceId = u32;
+
+/// Temporary alias for `crate::resources2::ResourceTable`.
+// TODO: remove this when the old `ResourceTable` is obsolete.
+pub type ResourceTable2 = ResourceTable;
+
+/// 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 {
+ index: HashMap<ResourceId, Rc<dyn Resource>>,
+ next_rid: ResourceId,
+}
+
+impl ResourceTable {
+ /// Returns true if any resource with the given `rid` is exists.
+ pub fn has(&self, rid: ResourceId) -> bool {
+ self.index.contains_key(&rid)
+ }
+
+ /// Returns a reference counted pointer to the resource of type `T` with the
+ /// given `rid`. If `rid` is not present or has a type different than `T`,
+ /// this function returns `None`.
+ pub fn get<T: Resource>(&self, rid: ResourceId) -> Option<Rc<T>> {
+ self
+ .index
+ .get(&rid)
+ .and_then(|resource| resource.downcast_rc::<T>())
+ .map(Clone::clone)
+ }
+
+ /// Inserts resource into the resource table, which takes 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<T: Resource>(&mut self, resource: T) -> ResourceId {
+ self.add_rc(Rc::new(resource))
+ }
+
+ /// Inserts a `Rc`-wrapped resource into the resource table.
+ ///
+ /// 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_rc<T: Resource>(&mut self, resource: Rc<T>) -> ResourceId {
+ let resource = resource as Rc<dyn Resource>;
+ let rid = self.next_rid;
+ let removed_resource = self.index.insert(rid, resource);
+ assert!(removed_resource.is_none());
+ self.next_rid += 1;
+ rid
+ }
+
+ /// Removes the resource with the given `rid` from the resource table. If the
+ /// only reference to this resource existed in the resource table, this will
+ /// cause the resource to be dropped. However, since resources are reference
+ /// counted, therefore pending ops are not automatically cancelled.
+ pub fn close(&mut self, rid: ResourceId) -> Option<()> {
+ self.index.remove(&rid).map(|_| ())
+ }
+
+ /// Returns an iterator that yields a `(id, name)` pair for every resource
+ /// that's currently in the resource table. This can be used for debugging
+ /// purposes or to implement the `op_resources` op. Note that the order in
+ /// which items appear is not specified.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// # use deno_core::resources2::ResourceTable;
+ /// # let resource_table = ResourceTable::default();
+ /// let resource_names = resource_table.names().collect::<Vec<_>>();
+ /// ```
+ pub fn names(&self) -> impl Iterator<Item = (ResourceId, Cow<str>)> {
+ self
+ .index
+ .iter()
+ .map(|(&id, resource)| (id, resource.name()))
+ }
+}