asset_cache.rs

 1use crate::{SharedUri, WindowContext};
 2use collections::FxHashMap;
 3use futures::Future;
 4use parking_lot::Mutex;
 5use std::any::TypeId;
 6use std::hash::{Hash, Hasher};
 7use std::sync::Arc;
 8use std::{any::Any, path::PathBuf};
 9
10#[derive(Debug, PartialEq, Eq, Hash, Clone)]
11pub(crate) enum UriOrPath {
12    Uri(SharedUri),
13    Path(Arc<PathBuf>),
14}
15
16impl From<SharedUri> for UriOrPath {
17    fn from(value: SharedUri) -> Self {
18        Self::Uri(value)
19    }
20}
21
22impl From<Arc<PathBuf>> for UriOrPath {
23    fn from(value: Arc<PathBuf>) -> Self {
24        Self::Path(value)
25    }
26}
27
28/// A trait for asynchronous asset loading.
29pub trait Asset {
30    /// The source of the asset.
31    type Source: Clone + Hash + Send;
32
33    /// The loaded asset
34    type Output: Clone + Send;
35
36    /// Load the asset asynchronously
37    fn load(
38        source: Self::Source,
39        cx: &mut WindowContext,
40    ) -> impl Future<Output = Self::Output> + Send + 'static;
41}
42
43/// Use a quick, non-cryptographically secure hash function to get an identifier from data
44pub fn hash<T: Hash>(data: &T) -> u64 {
45    let mut hasher = collections::FxHasher::default();
46    data.hash(&mut hasher);
47    hasher.finish()
48}
49
50/// A cache for assets.
51#[derive(Clone)]
52pub struct AssetCache {
53    assets: Arc<Mutex<FxHashMap<(TypeId, u64), Box<dyn Any + Send>>>>,
54}
55
56impl AssetCache {
57    pub(crate) fn new() -> Self {
58        Self {
59            assets: Default::default(),
60        }
61    }
62
63    /// Get the asset from the cache, if it exists.
64    pub fn get<A: Asset + 'static>(&self, source: &A::Source) -> Option<A::Output> {
65        self.assets
66            .lock()
67            .get(&(TypeId::of::<A>(), hash(&source)))
68            .and_then(|task| task.downcast_ref::<A::Output>())
69            .cloned()
70    }
71
72    /// Insert the asset into the cache.
73    pub fn insert<A: Asset + 'static>(&mut self, source: A::Source, output: A::Output) {
74        self.assets
75            .lock()
76            .insert((TypeId::of::<A>(), hash(&source)), Box::new(output));
77    }
78
79    /// Remove an entry from the asset cache
80    pub fn remove<A: Asset + 'static>(&mut self, source: &A::Source) -> Option<A::Output> {
81        self.assets
82            .lock()
83            .remove(&(TypeId::of::<A>(), hash(&source)))
84            .and_then(|any| any.downcast::<A::Output>().ok())
85            .map(|boxed| *boxed)
86    }
87}