asset_cache.rs

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