use std::collections::HashMap;
use std::path::{Path, PathBuf};
use super::asset_uuid::AssetUuid;
use super::manifest::{AssetEntry, AssetManifest, AssetType};
#[derive(Debug, Clone)]
pub struct AssetRegistry {
manifests: Vec<AssetManifest>,
uuid_to_manifest: HashMap<AssetUuid, usize>,
path_to_uuid: HashMap<String, AssetUuid>,
name_to_uuid: HashMap<String, AssetUuid>,
base_paths: Vec<PathBuf>,
}
impl Default for AssetRegistry {
fn default() -> Self {
Self::new()
}
}
impl AssetRegistry {
pub fn new() -> Self {
Self {
manifests: Vec::new(),
uuid_to_manifest: HashMap::new(),
path_to_uuid: HashMap::new(),
name_to_uuid: HashMap::new(),
base_paths: Vec::new(),
}
}
pub fn add_manifest(&mut self, manifest: AssetManifest, base_path: impl Into<PathBuf>) {
let manifest_index = self.manifests.len();
let base_path = base_path.into();
for entry in &manifest.assets {
self.uuid_to_manifest.insert(entry.uuid, manifest_index);
self.path_to_uuid.insert(entry.path.clone(), entry.uuid);
if let Some(name) = &entry.name {
self.name_to_uuid.insert(name.clone(), entry.uuid);
}
}
self.manifests.push(manifest);
self.base_paths.push(base_path);
}
pub fn resolve_uuid(&self, uuid: AssetUuid) -> Option<PathBuf> {
let manifest_index = self.uuid_to_manifest.get(&uuid)?;
let manifest = self.manifests.get(*manifest_index)?;
let entry = manifest.get_by_uuid(uuid)?;
let base_path = self.base_paths.get(*manifest_index)?;
Some(base_path.join(&entry.path))
}
pub fn resolve_path(&self, path: &str) -> Option<AssetUuid> {
self.path_to_uuid.get(path).copied()
}
pub fn resolve_name(&self, name: &str) -> Option<AssetUuid> {
self.name_to_uuid.get(name).copied()
}
pub fn get_entry(&self, uuid: AssetUuid) -> Option<&AssetEntry> {
let manifest_index = self.uuid_to_manifest.get(&uuid)?;
let manifest = self.manifests.get(*manifest_index)?;
manifest.get_by_uuid(uuid)
}
pub fn get_base_path(&self, uuid: AssetUuid) -> Option<&Path> {
let manifest_index = self.uuid_to_manifest.get(&uuid)?;
self.base_paths.get(*manifest_index).map(|p| p.as_path())
}
pub fn assets_of_type(&self, asset_type: AssetType) -> impl Iterator<Item = &AssetEntry> {
self.manifests
.iter()
.flat_map(move |manifest| manifest.assets_of_type(asset_type))
}
pub fn all_assets(&self) -> impl Iterator<Item = &AssetEntry> {
self.manifests.iter().flat_map(|manifest| &manifest.assets)
}
pub fn uuid_exists(&self, uuid: AssetUuid) -> bool {
self.uuid_to_manifest.contains_key(&uuid)
}
pub fn path_exists(&self, path: &str) -> bool {
self.path_to_uuid.contains_key(path)
}
pub fn name_exists(&self, name: &str) -> bool {
self.name_to_uuid.contains_key(name)
}
pub fn clear(&mut self) {
self.manifests.clear();
self.uuid_to_manifest.clear();
self.path_to_uuid.clear();
self.name_to_uuid.clear();
self.base_paths.clear();
}
pub fn manifest_count(&self) -> usize {
self.manifests.len()
}
pub fn asset_count(&self) -> usize {
self.manifests.iter().map(|m| m.len()).sum()
}
}
#[derive(Debug, Clone)]
pub struct RuntimeAssetEntry {
pub uuid: AssetUuid,
pub name: String,
pub asset_type: AssetType,
pub loaded: bool,
}
#[derive(Debug, Clone, Default)]
pub struct RuntimeAssetRegistry {
entries: HashMap<AssetUuid, RuntimeAssetEntry>,
name_to_uuid: HashMap<String, AssetUuid>,
type_to_uuids: HashMap<AssetType, Vec<AssetUuid>>,
}
impl RuntimeAssetRegistry {
pub fn new() -> Self {
Self::default()
}
pub fn register(&mut self, uuid: AssetUuid, name: impl Into<String>, asset_type: AssetType) {
let name = name.into();
let entry = RuntimeAssetEntry {
uuid,
name: name.clone(),
asset_type,
loaded: false,
};
self.name_to_uuid.insert(name, uuid);
self.type_to_uuids.entry(asset_type).or_default().push(uuid);
self.entries.insert(uuid, entry);
}
pub fn mark_loaded(&mut self, uuid: AssetUuid) {
if let Some(entry) = self.entries.get_mut(&uuid) {
entry.loaded = true;
}
}
pub fn mark_unloaded(&mut self, uuid: AssetUuid) {
if let Some(entry) = self.entries.get_mut(&uuid) {
entry.loaded = false;
}
}
pub fn is_loaded(&self, uuid: AssetUuid) -> bool {
self.entries.get(&uuid).is_some_and(|e| e.loaded)
}
pub fn get(&self, uuid: AssetUuid) -> Option<&RuntimeAssetEntry> {
self.entries.get(&uuid)
}
pub fn get_by_name(&self, name: &str) -> Option<&RuntimeAssetEntry> {
self.name_to_uuid
.get(name)
.and_then(|uuid| self.entries.get(uuid))
}
pub fn resolve_name(&self, name: &str) -> Option<AssetUuid> {
self.name_to_uuid.get(name).copied()
}
pub fn unregister(&mut self, uuid: AssetUuid) {
if let Some(entry) = self.entries.remove(&uuid) {
self.name_to_uuid.remove(&entry.name);
if let Some(uuids) = self.type_to_uuids.get_mut(&entry.asset_type) {
uuids.retain(|u| *u != uuid);
}
}
}
pub fn clear(&mut self) {
self.entries.clear();
self.name_to_uuid.clear();
self.type_to_uuids.clear();
}
}