rafx_framework/resources/
resource_arc.rs

1use crossbeam_channel::Sender;
2use std::fmt::Formatter;
3use std::hash::Hash;
4use std::sync::{Arc, Weak};
5
6//TODO: Maybe this should be an enum of ResourceHash and ResourceIndex
7
8// Hijack ResourceHash for now
9#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
10pub(crate) struct ResourceId(pub(crate) u64);
11
12//
13// A reference counted object that sends a signal when it's dropped
14//
15#[derive(Clone)]
16pub(crate) struct ResourceWithHash<ResourceT>
17where
18    ResourceT: Clone,
19{
20    pub(super) resource: ResourceT,
21    pub(super) resource_hash: ResourceId,
22}
23
24impl<ResourceT> std::fmt::Debug for ResourceWithHash<ResourceT>
25where
26    ResourceT: std::fmt::Debug + Clone,
27{
28    fn fmt(
29        &self,
30        f: &mut Formatter<'_>,
31    ) -> std::fmt::Result {
32        f.debug_struct("ResourceWithHash")
33            .field("resource", &self.resource)
34            .field("resource_hash", &self.resource_hash)
35            .finish()
36    }
37}
38
39struct ResourceArcInner<ResourceT>
40where
41    ResourceT: Clone,
42{
43    resource: ResourceWithHash<ResourceT>,
44    drop_tx: Sender<ResourceWithHash<ResourceT>>,
45}
46
47impl<ResourceT> Drop for ResourceArcInner<ResourceT>
48where
49    ResourceT: Clone,
50{
51    fn drop(&mut self) {
52        self.drop_tx.send(self.resource.clone())
53            .expect("A resource was dropped after the resource manager was destroyed, it might not clean up properly");
54    }
55}
56
57impl<ResourceT> std::fmt::Debug for ResourceArcInner<ResourceT>
58where
59    ResourceT: std::fmt::Debug + Clone,
60{
61    fn fmt(
62        &self,
63        f: &mut Formatter<'_>,
64    ) -> std::fmt::Result {
65        f.debug_struct("ResourceArcInner")
66            .field("resource", &self.resource)
67            .finish()
68    }
69}
70
71#[derive(Clone)]
72pub struct WeakResourceArc<ResourceT>
73where
74    ResourceT: Clone,
75{
76    inner: Weak<ResourceArcInner<ResourceT>>,
77    resource_hash: ResourceId,
78}
79
80impl<ResourceT> WeakResourceArc<ResourceT>
81where
82    ResourceT: Clone,
83{
84    pub fn upgrade(&self) -> Option<ResourceArc<ResourceT>> {
85        if let Some(upgrade) = self.inner.upgrade() {
86            Some(ResourceArc { inner: upgrade })
87        } else {
88            None
89        }
90    }
91}
92
93impl<ResourceT> std::fmt::Debug for WeakResourceArc<ResourceT>
94where
95    ResourceT: std::fmt::Debug + Clone,
96{
97    fn fmt(
98        &self,
99        f: &mut Formatter<'_>,
100    ) -> std::fmt::Result {
101        f.debug_struct("WeakResourceArc")
102            .field("inner", &self.inner)
103            .finish()
104    }
105}
106
107impl<ResourceT> PartialEq for WeakResourceArc<ResourceT>
108where
109    ResourceT: std::fmt::Debug + Clone,
110{
111    fn eq(
112        &self,
113        other: &Self,
114    ) -> bool {
115        self.resource_hash == other.resource_hash
116    }
117}
118
119impl<ResourceT> Eq for WeakResourceArc<ResourceT> where ResourceT: std::fmt::Debug + Clone {}
120
121impl<ResourceT> Hash for WeakResourceArc<ResourceT>
122where
123    ResourceT: std::fmt::Debug + Clone,
124{
125    fn hash<H: std::hash::Hasher>(
126        &self,
127        state: &mut H,
128    ) {
129        self.resource_hash.hash(state);
130    }
131}
132
133#[derive(Clone)]
134pub struct ResourceArc<ResourceT>
135where
136    ResourceT: Clone,
137{
138    inner: Arc<ResourceArcInner<ResourceT>>,
139}
140
141impl<ResourceT> ResourceArc<ResourceT>
142where
143    ResourceT: Clone,
144{
145    pub(crate) fn new(
146        resource: ResourceT,
147        resource_hash: ResourceId,
148        drop_tx: Sender<ResourceWithHash<ResourceT>>,
149    ) -> Self {
150        ResourceArc {
151            inner: Arc::new(ResourceArcInner {
152                resource: ResourceWithHash {
153                    resource,
154                    resource_hash,
155                },
156                drop_tx,
157            }),
158        }
159    }
160
161    pub fn get_raw(&self) -> ResourceT {
162        self.inner.resource.resource.clone()
163    }
164
165    //NOTE: This is highly likely to be unique, especially when comparing against like resources,
166    // but it's not absolutely guaranteed
167    pub(super) fn resource_hash(&self) -> ResourceId {
168        self.inner.resource.resource_hash
169    }
170
171    pub fn downgrade(&self) -> WeakResourceArc<ResourceT> {
172        let inner = Arc::downgrade(&self.inner);
173        let resource_hash = self.inner.resource.resource_hash;
174        WeakResourceArc {
175            inner,
176            resource_hash,
177        }
178    }
179}
180
181impl<ResourceT> std::fmt::Debug for ResourceArc<ResourceT>
182where
183    ResourceT: std::fmt::Debug + Clone,
184{
185    fn fmt(
186        &self,
187        f: &mut Formatter<'_>,
188    ) -> std::fmt::Result {
189        f.debug_struct("ResourceArc")
190            .field("inner", &self.inner)
191            .finish()
192    }
193}
194
195impl<ResourceT> PartialEq for ResourceArc<ResourceT>
196where
197    ResourceT: std::fmt::Debug + Clone,
198{
199    fn eq(
200        &self,
201        other: &Self,
202    ) -> bool {
203        self.inner.resource.resource_hash == other.inner.resource.resource_hash
204    }
205}
206
207impl<ResourceT> Eq for ResourceArc<ResourceT> where ResourceT: std::fmt::Debug + Clone {}
208
209impl<ResourceT> Hash for ResourceArc<ResourceT>
210where
211    ResourceT: std::fmt::Debug + Clone,
212{
213    fn hash<H: std::hash::Hasher>(
214        &self,
215        state: &mut H,
216    ) {
217        self.inner.resource.resource_hash.hash(state);
218    }
219}