use super::{
asset::{Asset, AssetTrait},
STORAGE_DIR,
};
use crate::{storage::AssetId, ui::action::UiAction};
use rayon::iter::{ParallelBridge, ParallelIterator};
use std::{collections::HashMap, fmt::Debug, str::FromStr, sync::Arc};
use typemap::Key;
use uuid::Uuid;
#[derive(Debug, Clone, Default)]
pub struct Collection<T: AssetTrait>(HashMap<Uuid, Arc<Asset<T>>>);
impl<T: AssetTrait + 'static> Key for Collection<T> {
type Value = Collection<T>;
}
impl<T: AssetTrait> Collection<T> {
pub fn load() -> Self {
let path = STORAGE_DIR.join(T::DIR_NAME);
let Ok(directory) = path.read_dir() else {
return Self(HashMap::new());
};
let folders = directory
.par_bridge()
.filter_map(|entry| {
let entry = entry
.map_err(|err| log::warn!("Could not read dir entry: {err:?}"))
.ok()?;
let file_type = entry
.file_type()
.map_err(|err| log::warn!("Could not get file type: {err:?}"))
.ok()?;
if file_type.is_file() {
let id = Uuid::from_str(
entry
.file_name()
.into_string()
.map_err(|err| {
log::warn!("Could not convert file name to string: {err:?}")
})
.ok()?
.strip_suffix(".json")?,
)
.map_err(|err| log::warn!("Could not parse UUID: {err:?}"))
.ok()?;
let asset = Asset::<T>::read(
std::fs::File::open(entry.path()).ok()?,
AssetId::from_uuid(id),
)
.map_err(|err| {
UiAction::Error(format!(
"Could not read/parse asset {}: {err:?}",
entry.path().display()
))
.enqueue();
})
.ok()?;
return Some((id, asset));
}
None
})
.collect();
Self(folders)
}
pub fn assets(&self) -> Vec<Arc<Asset<T>>> {
self.0.values().cloned().collect()
}
pub fn get(&self, id: &AssetId<T>) -> Option<&Arc<Asset<T>>> {
self.0.get(&id.id)
}
pub fn set_asset(&mut self, asset: Asset<T>) {
self.0.insert(asset.id.id, Arc::new(asset));
}
pub fn delete_asset(&mut self, id: AssetId<T>) {
self.0.remove(&id.id);
}
}