Skip to main content

goud_engine/assets/server/
loader_registry.rs

1//! Loader registration methods for `AssetServer`.
2
3use super::core::AssetServer;
4use crate::assets::{Asset, AssetId, AssetLoader, ErasedAssetLoader, TypedAssetLoader};
5
6impl AssetServer {
7    /// Registers an asset loader for specific file extensions.
8    ///
9    /// Loaders are matched by file extension. If multiple loaders support
10    /// the same extension, the most recently registered one is used.
11    ///
12    /// # Arguments
13    ///
14    /// * `loader` - The asset loader to register
15    ///
16    /// # Example
17    ///
18    /// ```no_run
19    /// use goud_engine::assets::{Asset, AssetServer, AssetLoader, LoadContext, AssetLoadError};
20    ///
21    /// #[derive(Clone)]
22    /// struct TextAsset { content: String }
23    /// impl Asset for TextAsset {}
24    ///
25    /// #[derive(Clone)]
26    /// struct TextLoader;
27    /// impl AssetLoader for TextLoader {
28    ///     type Asset = TextAsset;
29    ///     type Settings = ();
30    ///
31    ///     fn extensions(&self) -> &[&str] {
32    ///         &["txt"]
33    ///     }
34    ///
35    ///     fn load<'a>(
36    ///         &'a self,
37    ///         bytes: &'a [u8],
38    ///         _settings: &'a Self::Settings,
39    ///         _context: &'a mut LoadContext,
40    ///     ) -> Result<Self::Asset, AssetLoadError> {
41    ///         let content = String::from_utf8(bytes.to_vec())
42    ///             .map_err(|e| AssetLoadError::decode_failed(e.to_string()))?;
43    ///         Ok(TextAsset { content })
44    ///     }
45    /// }
46    ///
47    /// let mut server = AssetServer::new();
48    /// server.register_loader(TextLoader);
49    /// ```
50    pub fn register_loader<L: AssetLoader>(&mut self, loader: L) {
51        let typed = TypedAssetLoader::new(loader);
52        let asset_id = AssetId::of::<L::Asset>();
53
54        // Register by extensions
55        for extension in typed.extensions() {
56            let ext = extension.to_lowercase();
57            self.loaders.insert(ext, Box::new(typed.clone()));
58        }
59
60        // Register by asset type
61        self.loader_by_type.insert(asset_id, Box::new(typed));
62    }
63
64    /// Registers an asset loader with custom settings.
65    ///
66    /// # Arguments
67    ///
68    /// * `loader` - The asset loader to register
69    /// * `settings` - Custom settings for this loader
70    pub fn register_loader_with_settings<L: AssetLoader>(
71        &mut self,
72        loader: L,
73        settings: L::Settings,
74    ) {
75        let typed = TypedAssetLoader::with_settings(loader, settings);
76        let asset_id = AssetId::of::<L::Asset>();
77
78        for extension in typed.extensions() {
79            let ext = extension.to_lowercase();
80            self.loaders.insert(ext, Box::new(typed.clone()));
81        }
82
83        self.loader_by_type.insert(asset_id, Box::new(typed));
84    }
85
86    /// Returns true if a loader is registered for the given extension.
87    ///
88    /// # Example
89    ///
90    /// ```
91    /// use goud_engine::assets::AssetServer;
92    ///
93    /// let server = AssetServer::new();
94    /// // Assuming TextLoader is registered for "txt"
95    /// // assert!(server.has_loader_for_extension("txt"));
96    /// assert!(!server.has_loader_for_extension("unknown"));
97    /// ```
98    pub fn has_loader_for_extension(&self, extension: &str) -> bool {
99        self.loaders.contains_key(&extension.to_lowercase())
100    }
101
102    /// Returns true if a loader is registered for the given asset type.
103    pub fn has_loader_for_type<A: Asset>(&self) -> bool {
104        self.loader_by_type.contains_key(&AssetId::of::<A>())
105    }
106
107    /// Returns the number of registered loaders.
108    #[inline]
109    pub fn loader_count(&self) -> usize {
110        self.loader_by_type.len()
111    }
112}