Skip to main content

cljrs_value/
resource.rs

1//! The `Resource` trait for I/O handles and other closeable resources.
2//!
3//! Resources are ref-counted with `Arc` (NOT `GcPtr`) so that they get
4//! deterministic cleanup when the last reference drops.  The GC has no
5//! finalizers, so `GcPtr` would leak file descriptors.
6
7use std::any::Any;
8use std::fmt;
9use std::sync::Arc;
10
11use crate::error::ValueResult;
12
13/// A closeable, ref-counted resource (file handle, socket, etc.).
14///
15/// All methods take `&self` because the inner state is behind a `Mutex`.
16pub trait Resource: Send + Sync + fmt::Debug + 'static {
17    /// Close the resource.  Idempotent — calling on an already-closed
18    /// resource is a no-op.
19    fn close(&self) -> ValueResult<()>;
20
21    /// Whether this resource has been closed.
22    fn is_closed(&self) -> bool;
23
24    /// A short tag for display, e.g. `"reader"`, `"writer"`.
25    fn resource_type(&self) -> &'static str;
26
27    /// Downcast support so native fns can get the concrete type.
28    fn as_any(&self) -> &dyn Any;
29}
30
31/// A wrapper around `Arc<dyn Resource>` that provides `Clone` and `Debug`.
32#[derive(Clone)]
33pub struct ResourceHandle(pub Arc<dyn Resource>);
34
35impl fmt::Debug for ResourceHandle {
36    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
37        write!(f, "Resource({})", self.0.resource_type())
38    }
39}
40
41impl ResourceHandle {
42    pub fn new(r: impl Resource) -> Self {
43        Self(Arc::new(r))
44    }
45
46    pub fn close(&self) -> ValueResult<()> {
47        self.0.close()
48    }
49
50    pub fn is_closed(&self) -> bool {
51        self.0.is_closed()
52    }
53
54    pub fn resource_type(&self) -> &'static str {
55        self.0.resource_type()
56    }
57
58    /// Attempt to downcast to a concrete resource type.
59    pub fn downcast<T: Resource>(&self) -> Option<&T> {
60        self.0.as_any().downcast_ref::<T>()
61    }
62}