keket/database/
reference.rs1use crate::database::{
2 AssetDatabase, AssetDatabaseCommandsSender, AssetReferenceCounter, handle::AssetHandle,
3 path::AssetPathStatic,
4};
5use anput::{entity::Entity, query::TypedLookupFetch};
6use serde::{Deserialize, Serialize};
7use std::{
8 error::Error,
9 ops::{Deref, DerefMut},
10 sync::RwLock,
11};
12
13#[derive(Debug, Serialize, Deserialize)]
18#[serde(from = "AssetPathStatic", into = "AssetPathStatic")]
19pub struct AssetRef {
20 path: AssetPathStatic,
21 #[serde(skip)]
22 handle: RwLock<Option<AssetHandle>>,
23}
24
25impl Default for AssetRef {
26 fn default() -> Self {
27 Self::new("")
28 }
29}
30
31impl AssetRef {
32 pub fn new(path: impl Into<AssetPathStatic>) -> Self {
40 Self {
41 path: path.into(),
42 handle: RwLock::new(None),
43 }
44 }
45
46 pub fn new_resolved(path: impl Into<AssetPathStatic>, handle: AssetHandle) -> Self {
55 Self {
56 path: path.into(),
57 handle: RwLock::new(Some(handle)),
58 }
59 }
60
61 pub fn invalidate(&self) -> Result<(), Box<dyn Error>> {
66 *self.handle.write().map_err(|error| format!("{error}"))? = None;
67 Ok(())
68 }
69
70 pub fn path(&self) -> &AssetPathStatic {
75 &self.path
76 }
77
78 pub fn handle(&self) -> Result<AssetHandle, Box<dyn Error>> {
83 self.handle
84 .read()
85 .map_err(|error| format!("{error}"))?
86 .ok_or_else(|| format!("Asset with `{}` path is not yet resolved!", self.path).into())
87 }
88
89 pub fn resolve<'a>(
97 &'a self,
98 database: &'a AssetDatabase,
99 ) -> Result<AssetResolved<'a>, Box<dyn Error>> {
100 let mut handle = self.handle.write().map_err(|error| format!("{error}"))?;
101 if let Some(result) = handle.as_ref() {
102 Ok(AssetResolved::new(*result, database))
103 } else {
104 let result = database
105 .find(self.path.clone())
106 .ok_or_else(|| format!("Asset with `{}` path not found in database!", self.path))?;
107 *handle = Some(result);
108 Ok(AssetResolved::new(result, database))
109 }
110 }
111
112 pub fn ensure<'a>(
120 &'a self,
121 database: &'a mut AssetDatabase,
122 ) -> Result<AssetResolved<'a>, Box<dyn Error>> {
123 let mut handle = self.handle.write().map_err(|error| format!("{error}"))?;
124 if let Some(result) = handle.as_ref() {
125 Ok(AssetResolved::new(*result, database))
126 } else {
127 let result = database.ensure(self.path.clone())?;
128 *handle = Some(result);
129 Ok(AssetResolved::new(result, database))
130 }
131 }
132}
133
134impl Clone for AssetRef {
135 fn clone(&self) -> Self {
136 Self {
137 path: self.path.clone(),
138 handle: RwLock::new(
139 self.handle
140 .try_read()
141 .ok()
142 .map(|handle| *handle)
143 .unwrap_or_default(),
144 ),
145 }
146 }
147}
148
149impl PartialEq for AssetRef {
150 fn eq(&self, other: &Self) -> bool {
151 self.path.eq(&other.path)
152 }
153}
154
155impl Eq for AssetRef {}
156
157impl From<AssetPathStatic> for AssetRef {
158 fn from(path: AssetPathStatic) -> Self {
159 Self::new(path)
160 }
161}
162
163impl From<AssetRef> for AssetPathStatic {
164 fn from(value: AssetRef) -> Self {
165 value.path
166 }
167}
168
169pub struct AssetResolved<'a> {
173 handle: AssetHandle,
174 database: &'a AssetDatabase,
175}
176
177impl<'a> AssetResolved<'a> {
178 pub fn new(handle: AssetHandle, database: &'a AssetDatabase) -> Self {
187 Self { handle, database }
188 }
189
190 pub fn entity(&self) -> Entity {
192 self.handle.entity()
193 }
194
195 pub fn does_exists(&self) -> bool {
197 self.handle.does_exists(self.database)
198 }
199
200 pub fn awaits_storing(self) -> bool {
202 self.handle.awaits_storing(self.database)
203 }
204
205 pub fn bytes_are_ready_to_store(self) -> bool {
207 self.handle.bytes_are_ready_to_store(self.database)
208 }
209
210 pub fn awaits_async_store(self) -> bool {
212 self.handle.awaits_async_store(self.database)
213 }
214
215 pub fn awaits_resolution(&self) -> bool {
217 self.handle.awaits_resolution(self.database)
218 }
219
220 pub fn bytes_are_ready_to_process(&self) -> bool {
222 self.handle.bytes_are_ready_to_process(self.database)
223 }
224
225 pub fn awaits_async_fetch(&self) -> bool {
227 self.handle.awaits_async_fetch(self.database)
228 }
229
230 pub fn is_ready_to_use(&self) -> bool {
232 self.handle.is_ready_to_use(self.database)
233 }
234
235 pub async fn wait_for_ready_to_use(&self) {
237 self.handle.wait_for_ready_to_use(self.database).await
238 }
239
240 pub fn access_checked<'b, Fetch: TypedLookupFetch<'b, true>>(&'b self) -> Option<Fetch::Value> {
245 self.handle.access_checked::<Fetch>(self.database)
246 }
247
248 pub fn access<'b, Fetch: TypedLookupFetch<'b, true>>(&'b self) -> Fetch::Value {
253 self.handle.access::<Fetch>(self.database)
254 }
255
256 pub fn dependencies(&self) -> impl Iterator<Item = AssetRef> + '_ {
258 self.handle
259 .dependencies(self.database)
260 .filter_map(|handle| {
261 Some(AssetRef::new_resolved(
262 handle
263 .access_checked::<&AssetPathStatic>(self.database)?
264 .clone(),
265 handle,
266 ))
267 })
268 }
269
270 pub fn dependent(&self) -> impl Iterator<Item = AssetRef> + '_ {
272 self.handle.dependent(self.database).filter_map(|handle| {
273 Some(AssetRef::new_resolved(
274 handle
275 .access_checked::<&AssetPathStatic>(self.database)?
276 .clone(),
277 handle,
278 ))
279 })
280 }
281
282 pub fn traverse_dependencies(&self) -> impl Iterator<Item = AssetRef> + '_ {
284 self.handle
285 .traverse_dependencies(self.database)
286 .filter_map(|handle| {
287 Some(AssetRef::new_resolved(
288 handle
289 .access_checked::<&AssetPathStatic>(self.database)?
290 .clone(),
291 handle,
292 ))
293 })
294 }
295}
296
297pub struct SmartAssetRef {
300 inner: AssetRef,
301 sender: AssetDatabaseCommandsSender,
302}
303
304impl Drop for SmartAssetRef {
305 fn drop(&mut self) {
306 if let Ok(handle) = self.inner.handle() {
307 self.sender.send(Box::new(move |storage| {
308 if let Ok(mut counter) =
309 storage.component_mut::<true, AssetReferenceCounter>(handle.entity())
310 {
311 counter.decrement();
312 storage.update::<AssetReferenceCounter>(handle.entity());
313 }
314 }));
315 }
316 }
317}
318
319impl SmartAssetRef {
320 pub fn new(
330 path: impl Into<AssetPathStatic>,
331 database: &mut AssetDatabase,
332 ) -> Result<Self, Box<dyn Error>> {
333 Self::from_ref(AssetRef::new(path), database)
334 }
335
336 pub fn from_ref(inner: AssetRef, database: &mut AssetDatabase) -> Result<Self, Box<dyn Error>> {
346 let sender = database.commands_sender();
347 let handle = inner.ensure(database)?.handle;
348 handle
349 .ensure::<AssetReferenceCounter>(database)?
350 .increment();
351 database
352 .storage
353 .update::<AssetReferenceCounter>(handle.entity());
354 Ok(Self { inner, sender })
355 }
356
357 pub fn into_ref(self) -> AssetRef {
360 self.inner.clone()
361 }
362}
363
364impl Clone for SmartAssetRef {
365 fn clone(&self) -> Self {
366 if let Ok(handle) = self.inner.handle() {
367 self.sender.send(Box::new(move |storage| {
368 if let Ok(mut counter) =
369 storage.component_mut::<true, AssetReferenceCounter>(handle.entity())
370 {
371 counter.increment();
372 storage.update::<AssetReferenceCounter>(handle.entity());
373 }
374 }));
375 }
376 Self {
377 inner: self.inner.clone(),
378 sender: self.sender.clone(),
379 }
380 }
381}
382
383impl Deref for SmartAssetRef {
384 type Target = AssetRef;
385
386 fn deref(&self) -> &Self::Target {
387 &self.inner
388 }
389}
390
391impl DerefMut for SmartAssetRef {
392 fn deref_mut(&mut self) -> &mut Self::Target {
393 &mut self.inner
394 }
395}