From ee6e010611433f0aad53e3c99571b8a8c6ca13f4 Mon Sep 17 00:00:00 2001 From: HampusM Date: Sun, 27 Sep 2026 20:28:24 +0200 Subject: refactor(engine): make asset importers per asset type --- engine/src/asset.rs | 204 +++++++++++++++++++++++++--------------------------- 1 file changed, 99 insertions(+), 105 deletions(-) (limited to 'engine/src/asset.rs') diff --git a/engine/src/asset.rs b/engine/src/asset.rs index 8337f5f..781ca22 100644 --- a/engine/src/asset.rs +++ b/engine/src/asset.rs @@ -1,9 +1,8 @@ -use std::any::{type_name, Any}; +use std::any::{type_name, Any, TypeId}; use std::borrow::Cow; use std::cell::RefCell; use std::collections::HashMap; use std::convert::Infallible; -use std::ffi::{OsStr, OsString}; use std::fmt::{Debug, Display}; use std::hash::{DefaultHasher, Hash, Hasher}; use std::hint::cold_path; @@ -28,6 +27,8 @@ declare_entity! { pub HANDLE_ASSETS_PHASE: (Phase, pair!(ChildOf, { *PRE_UPDATE_PHASE })); } +pub trait Asset: Send + Sync + 'static {} + /// Asset label. #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Label<'a> @@ -129,8 +130,7 @@ pub struct Assets { store: Vec, asset_lookup: RefCell>, - importers: Vec, - importer_lookup: HashMap, + importers: hashbrown::HashMap, import_work_queue: WorkQueue, import_work_msg_receiver: MpscReceiver, import_work_msg_sender: MpscSender, @@ -148,8 +148,7 @@ impl Assets Self { store: Vec::with_capacity(capacity), asset_lookup: RefCell::new(HashMap::with_capacity(capacity)), - importers: Vec::new(), - importer_lookup: HashMap::new(), + importers: hashbrown::HashMap::new(), import_work_queue: WorkQueue::new("asset_importing_work_queue"), import_work_msg_receiver, import_work_msg_sender, @@ -157,34 +156,25 @@ impl Assets } } - pub fn set_importer<'file_ext, AssetSettings, Err>( + pub fn set_importer( &mut self, - file_extensions: impl IntoIterator>>, func: impl Fn(&mut Submitter<'_>, &Path, Option<&AssetSettings>) -> Result<(), Err>, ) where + AssetT: Asset, AssetSettings: 'static, Err: std::error::Error + Send + Sync + 'static, { - self.importers.push(WrappedImporterFn::new(func)); - - let importer_index = self.importers.len() - 1; - - self.importer_lookup - .extend(file_extensions.into_iter().map(|file_ext| { - let file_ext: Cow = file_ext.into(); - - (file_ext.into_owned().into(), importer_index) - })); + self.importers + .insert(AssetTypeId::of::(), WrappedImporterFn::new(func)); } #[tracing::instrument( skip_all, - fields(asset_label, asset_type = type_name::()) + fields(asset_label, asset_type = type_name::()) )] - pub fn get( - &self, - handle: &Handle, - ) -> Option<&Asset> + pub fn get(&self, handle: &Handle) -> Option<&AssetT> + where + AssetT: Asset, { let id = handle.id.into_valid()?; @@ -203,7 +193,7 @@ impl Assets unreachable!(); }; - let Some(asset) = stored_asset.strong.downcast_ref::() else { + let Some(asset) = stored_asset.strong.downcast_ref::() else { tracing::error!("Wrong asset type"); return None; }; @@ -211,11 +201,13 @@ impl Assets Some(asset) } - #[tracing::instrument(skip_all, fields(asset_type=type_name::()))] - pub fn get_handle_to_loaded<'label, Asset: 'static + Send + Sync>( + #[tracing::instrument(skip_all, fields(asset_type=type_name::()))] + pub fn get_handle_to_loaded<'label, AssetT>( &self, label: impl Into>, - ) -> Option> + ) -> Option> + where + AssetT: Asset, { let label = label.into(); @@ -231,7 +223,7 @@ impl Assets unreachable!(); }; - if stored_asset.strong.downcast_ref::().is_none() { + if stored_asset.strong.downcast_ref::().is_none() { tracing::error!("Wrong asset type"); return None; } @@ -239,10 +231,9 @@ impl Assets Some(Handle::new(label_hash)) } - pub fn is_loaded_and_has_type( - &self, - handle: &Handle, - ) -> bool + pub fn is_loaded_and_has_type(&self, handle: &Handle) -> bool + where + AssetT: Asset, { let Some(id) = handle.id.into_valid() else { return false; @@ -260,13 +251,12 @@ impl Assets unreachable!(); }; - stored_asset.strong.downcast_ref::().is_some() + stored_asset.strong.downcast_ref::().is_some() } - pub fn get_label( - &self, - handle: &Handle, - ) -> Option + pub fn get_label(&self, handle: &Handle) -> Option + where + AssetT: Asset, { let id = handle.id.into_valid()?; @@ -293,10 +283,9 @@ impl Assets } #[tracing::instrument(skip(self))] - pub fn load<'i, Asset: 'static + Send + Sync>( - &self, - label: impl Into> + Debug, - ) -> Handle + pub fn load<'i, AssetT>(&self, label: impl Into> + Debug) -> Handle + where + AssetT: Asset, { let label = label.into(); @@ -309,7 +298,7 @@ impl Assets } let Some(lookup_entry) = asset_lookup.get(&label_hash) else { - self.add_import_work::( + self.add_import_work::( &label, label_hash, None, @@ -325,8 +314,8 @@ impl Assets unreachable!(); }; - if stored_asset.strong.downcast_ref::().is_none() { - tracing::error!("Wrong asset type {}", type_name::()); + if stored_asset.strong.downcast_ref::().is_none() { + tracing::error!("Wrong asset type {}", type_name::()); } } LookupEntry::Pending => {} @@ -336,13 +325,13 @@ impl Assets } #[tracing::instrument(skip(self))] - pub fn load_with_settings<'i, Asset, AssetSettings>( + pub fn load_with_settings<'i, AssetT, AssetSettings>( &self, label: impl Into> + Debug, asset_settings: AssetSettings, - ) -> Handle + ) -> Handle where - Asset: Send + Sync + 'static, + AssetT: Asset, AssetSettings: Send + Sync + Debug + 'static, { let label = label.into(); @@ -356,7 +345,7 @@ impl Assets } let Some(lookup_entry) = asset_lookup.get(&label_hash) else { - self.add_import_work::( + self.add_import_work::( &label, label_hash, Some(asset_settings), @@ -372,10 +361,10 @@ impl Assets unreachable!(); }; - if stored_asset.strong.downcast_ref::().is_none() { + if stored_asset.strong.downcast_ref::().is_none() { tracing::error!( "Wrong asset type {} for asset", - type_name::() + type_name::() ); } } @@ -385,11 +374,13 @@ impl Assets Handle::new(label_hash) } - pub fn store_with_name<'name, Asset: 'static + Send + Sync>( + pub fn store_with_name<'name, AssetT>( &mut self, name: impl Into>, - asset: Asset, - ) -> Handle + asset: AssetT, + ) -> Handle + where + AssetT: Asset, { self.store_with_label( Label { @@ -400,11 +391,13 @@ impl Assets ) } - pub fn store_with_name_with<'name, Asset: 'static + Send + Sync>( + pub fn store_with_name_with<'name, AssetT>( &mut self, name: impl Into>, - func: impl FnOnce(&mut Self) -> Asset, - ) -> Handle + func: impl FnOnce(&mut Self) -> AssetT, + ) -> Handle + where + AssetT: Asset, { let asset = func(self); @@ -417,12 +410,14 @@ impl Assets ) } - #[tracing::instrument(skip(self, asset), fields(asset_type=type_name::()))] - pub fn store_with_label<'i, Asset: 'static + Send + Sync>( + #[tracing::instrument(skip(self, asset), fields(asset_type=type_name::()))] + pub fn store_with_label<'i, AssetT>( &mut self, label: impl Into> + Debug, - asset: Asset, - ) -> Handle + asset: AssetT, + ) -> Handle + where + AssetT: Asset, { let label = label.into(); @@ -483,25 +478,18 @@ impl Assets false } - fn add_import_work( + fn add_import_work( &self, label: &Label<'_>, label_hash: LabelHash, asset_settings: Option, asset_lookup: &mut HashMap, ) where + AssetT: Asset, AssetSettings: Any + Send + Sync, { - let Some(file_ext) = label.path.extension() else { - tracing::error!("Asset file is missing a file extension"); - return; - }; - - let Some(importer) = self.get_importer(file_ext) else { - tracing::error!( - "No importer exists for asset file extension {}", - file_ext.to_string_lossy() - ); + let Some(importer) = self.importers.get(&AssetTypeId::of::()) else { + tracing::error!("No importer exists for asset"); return; }; @@ -546,17 +534,6 @@ impl Assets ); } } - - fn get_importer(&self, file_ext: &OsStr) -> Option<&WrappedImporterFn> - { - let index = *self.importer_lookup.get(file_ext)?; - - let Some(importer) = self.importers.get(index) else { - unreachable!(); - }; - - Some(importer) - } } impl Default for Assets @@ -575,16 +552,18 @@ pub struct Submitter<'path> impl Submitter<'_> { - pub fn submit_load_other<'label, Asset: Send + Sync + 'static>( + pub fn submit_load_other<'label, AssetT>( &self, label: impl Into>, - ) -> Handle + ) -> Handle + where + AssetT: Asset, { let label = label.into(); let _ = self.import_work_msg_sender.send(ImportWorkMessage::Load { do_load: |assets, label, _asset_settings| { - let _ = assets.load::(label); + let _ = assets.load::(label); }, label: label.to_owned(), asset_settings: None, @@ -593,13 +572,13 @@ impl Submitter<'_> Handle::new(LabelHash::new(&label)) } - pub fn submit_load_other_with_settings<'label, Asset, AssetSettings>( + pub fn submit_load_other_with_settings<'label, AssetT, AssetSettings>( &self, label: impl Into>, asset_settings: AssetSettings, - ) -> Handle + ) -> Handle where - Asset: Send + Sync + 'static, + AssetT: Asset, AssetSettings: Send + Sync + Debug + 'static, { let label = label.into(); @@ -612,7 +591,7 @@ impl Submitter<'_> .expect("Not possible"); let _ = assets - .load_with_settings::(label, asset_settings); + .load_with_settings::(label, asset_settings); }, label: label.to_owned(), asset_settings: Some(Box::new(asset_settings)), @@ -621,10 +600,9 @@ impl Submitter<'_> Handle::new(LabelHash::new(&label)) } - pub fn submit_store( - &self, - asset: Asset, - ) -> Handle + pub fn submit_store(&self, asset: AssetT) -> Handle + where + AssetT: Asset, { let label = LabelOwned { path: self.asset_path.into(), @@ -635,11 +613,11 @@ impl Submitter<'_> let _ = self.import_work_msg_sender.send(ImportWorkMessage::Store { do_store: |assets, label, boxed_asset| { - let Ok(asset) = boxed_asset.downcast::() else { + let Ok(asset) = boxed_asset.downcast::() else { unreachable!(); }; - assets.store_with_label::(&label, *asset); + assets.store_with_label::(&label, *asset); }, label, asset: Box::new(asset), @@ -648,11 +626,13 @@ impl Submitter<'_> Handle::new(label_hash) } - pub fn submit_store_named( + pub fn submit_store_named( &self, name: impl AsRef, - asset: Asset, - ) -> Handle + asset: AssetT, + ) -> Handle + where + AssetT: Asset, { let label = LabelOwned { path: self.asset_path.into(), @@ -663,11 +643,11 @@ impl Submitter<'_> let _ = self.import_work_msg_sender.send(ImportWorkMessage::Store { do_store: |assets, label, boxed_asset| { - let Ok(asset) = boxed_asset.downcast::() else { + let Ok(asset) = boxed_asset.downcast::() else { unreachable!(); }; - assets.store_with_label::(&label, *asset); + assets.store_with_label::(&label, *asset); }, label, asset: Box::new(asset), @@ -679,13 +659,13 @@ impl Submitter<'_> /// Asset handle. #[derive(Debug)] -pub struct Handle +pub struct Handle { id: Id, - _pd: PhantomData, + _pd: PhantomData, } -impl Handle +impl Handle { pub fn invalid() -> Self { @@ -712,7 +692,7 @@ impl Handle } } -impl Clone for Handle +impl Clone for Handle { fn clone(&self) -> Self { @@ -974,10 +954,24 @@ struct StoredAsset impl StoredAsset { - fn new(asset: Asset) -> Self + fn new(asset: AssetT) -> Self { let strong = Arc::new(asset); Self { strong } } } + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +struct AssetTypeId +{ + inner: TypeId, +} + +impl AssetTypeId +{ + fn of() -> Self + { + Self { inner: TypeId::of::() } + } +} -- cgit v1.2.3-18-g5258