use std::collections::HashMap;
use std::sync::{Arc, Weak};
use downcast_rs::{DowncastSync, impl_downcast};
use parking_lot::Mutex;
use crate::asset::{Asset, AssetId, AssetSerializationBackend, NullSerializationBackend};
use crate::asset_type::AssetType;
use crate::filesystem::{Filesystem, FilesystemError};
use crate::util::U64HashMap;
pub struct AssetManager {
asset_types: Mutex<HashMap<String, Arc<dyn AssetType>>>,
assets: Mutex<U64HashMap<AssetId, Arc<Asset>>>,
filesystem: Arc<dyn Filesystem>,
context: Option<Arc<dyn AssetManagerContext>>,
serialization: Box<dyn AssetSerializationBackend>,
}
impl AssetManager {
#[inline]
pub fn new(filesystem: Arc<dyn Filesystem>) -> Self {
Self {
asset_types: Mutex::new(HashMap::default()),
assets: Mutex::new(HashMap::default()),
filesystem,
context: None,
serialization: Box::new(NullSerializationBackend),
}
}
#[inline]
pub fn context(&self) -> Option<Arc<dyn AssetManagerContext>> {
self.context.clone()
}
#[inline]
pub fn set_context(&mut self, context: Arc<dyn AssetManagerContext>) {
self.context = Some(context);
}
pub fn set_serialization_backend(&mut self, serialization: Box<dyn AssetSerializationBackend>) {
self.serialization = serialization;
}
#[inline]
pub fn asset_type_by_name(&self, name: &str) -> Option<Weak<dyn AssetType>> {
let asset_types = self.asset_types.lock();
asset_types.get(name).map(Arc::downgrade)
}
pub fn register_asset_type(&self, asset_type: Arc<dyn AssetType>) {
self.asset_types
.lock()
.insert(asset_type.name().to_string(), asset_type);
}
#[inline]
pub fn asset_by_id(&self, id: AssetId) -> Option<Arc<Asset>> {
let assets = self.assets.lock();
assets.get(&id).cloned()
}
pub fn register_asset(&self, asset_path: &str, mut asset: Asset) -> AssetId {
let id = if asset.id() == AssetId::default() {
let new_id = AssetId::from(asset_path);
asset.set_id(new_id);
new_id
} else {
asset.id()
};
self.assets.lock().insert(id, Arc::new(asset));
id
}
pub fn unregister_asset(&self, id: AssetId) -> bool {
self.assets.lock().remove(&id).is_some()
}
#[inline]
pub async fn fs_read_bytes(&self, asset_path: &str) -> Result<Vec<u8>, FilesystemError> {
self.filesystem.read_bytes(asset_path).await
}
pub async fn fs_read_and_register_asset(&self, asset_path: &str) -> anyhow::Result<AssetId> {
let bytes = self.fs_read_bytes(asset_path).await?;
let serialized = self.serialization.deserialize(&bytes[..])?;
let asset = Asset::from_serialized(self, serialized)?;
Ok(self.register_asset(asset_path, asset))
}
}
pub trait AssetManagerContext: DowncastSync {}
impl_downcast!(sync AssetManagerContext);