zed/crates/gpui/src/asset_cache.rs
Matthias Grandl f9becbd3d1
gpui: Add SVG rendering to img element and generic asset cache (#9931)
This is a follow up to #9436 . It has a cleaner API and generalized the
image_cache to be a generic asset cache, that all GPUI elements can make
use off. The changes have been discussed with @mikayla-maki on Discord.

---------

Co-authored-by: Mikayla <mikayla@zed.dev>
2024-03-29 17:09:49 -07:00

87 lines
2.3 KiB
Rust

use crate::{SharedUri, WindowContext};
use collections::FxHashMap;
use futures::Future;
use parking_lot::Mutex;
use std::any::TypeId;
use std::hash::{Hash, Hasher};
use std::sync::Arc;
use std::{any::Any, path::PathBuf};
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
pub(crate) enum UriOrPath {
Uri(SharedUri),
Path(Arc<PathBuf>),
}
impl From<SharedUri> for UriOrPath {
fn from(value: SharedUri) -> Self {
Self::Uri(value)
}
}
impl From<Arc<PathBuf>> for UriOrPath {
fn from(value: Arc<PathBuf>) -> Self {
Self::Path(value)
}
}
/// A trait for asynchronous asset loading.
pub trait Asset {
/// The source of the asset.
type Source: Clone + Hash + Send;
/// The loaded asset
type Output: Clone + Send;
/// Load the asset asynchronously
fn load(
source: Self::Source,
cx: &mut WindowContext,
) -> impl Future<Output = Self::Output> + Send + 'static;
}
/// Use a quick, non-cryptographically secure hash function to get an identifier from data
pub fn hash<T: Hash>(data: &T) -> u64 {
let mut hasher = collections::FxHasher::default();
data.hash(&mut hasher);
hasher.finish()
}
/// A cache for assets.
#[derive(Clone)]
pub struct AssetCache {
assets: Arc<Mutex<FxHashMap<(TypeId, u64), Box<dyn Any + Send>>>>,
}
impl AssetCache {
pub(crate) fn new() -> Self {
Self {
assets: Default::default(),
}
}
/// Get the asset from the cache, if it exists.
pub fn get<A: Asset + 'static>(&self, source: &A::Source) -> Option<A::Output> {
self.assets
.lock()
.get(&(TypeId::of::<A>(), hash(&source)))
.and_then(|task| task.downcast_ref::<A::Output>())
.cloned()
}
/// Insert the asset into the cache.
pub fn insert<A: Asset + 'static>(&mut self, source: A::Source, output: A::Output) {
self.assets
.lock()
.insert((TypeId::of::<A>(), hash(&source)), Box::new(output));
}
/// Remove an entry from the asset cache
pub fn remove<A: Asset + 'static>(&mut self, source: &A::Source) -> Option<A::Output> {
self.assets
.lock()
.remove(&(TypeId::of::<A>(), hash(&source)))
.and_then(|any| any.downcast::<A::Output>().ok())
.map(|boxed| *boxed)
}
}