swamp_assets_loader/
lib.rs1use std::any::{type_name, TypeId};
6use std::collections::HashMap;
7use std::fmt::Debug;
8use std::io;
9use std::io::Error;
10use std::sync::{Arc, Mutex};
11use swamp_app::prelude::{App, Plugin, Resource};
12use swamp_assets::prelude::{Asset, RawWeakId};
13pub use swamp_resource::ResourceStorage;
14use tracing::debug;
15
16#[derive(Debug)]
17pub enum LoadError {
18 MissingLoader(RawWeakId),
19 ConversionError(ConversionError),
20 Downcast,
21}
22
23#[derive(Debug)]
24pub enum ConversionError {
25 WrongFormat,
26 IoError(io::Error),
27}
28
29impl From<ConversionError> for LoadError {
30 fn from(err: ConversionError) -> Self {
31 Self::ConversionError(err)
32 }
33}
34
35impl From<io::Error> for ConversionError {
36 fn from(value: Error) -> Self {
37 Self::IoError(value)
38 }
39}
40
41pub trait AssetLoader: Send + Sync {
42 type AssetType: Asset + 'static;
43
44 fn convert_and_insert(
47 &self,
48 id: RawWeakId,
49 octets: &[u8],
50 world: &mut ResourceStorage,
51 ) -> Result<(), ConversionError>;
52}
53
54type TypeIdMap<T> = HashMap<TypeId, T>;
55
56pub trait AnyAssetLoader: Send + Sync {
57 fn convert_and_insert_erased(
60 &self,
61 id: RawWeakId,
62 octets: &[u8],
63 resources: &mut ResourceStorage,
64 ) -> Result<(), LoadError>;
65
66 fn asset_type_id(&self) -> TypeId;
67}
68
69impl<T> AnyAssetLoader for T
70where
71 T: AssetLoader + 'static,
72{
73 fn convert_and_insert_erased(
74 &self,
75 id: RawWeakId,
76 octets: &[u8],
77 resources: &mut ResourceStorage,
78 ) -> Result<(), LoadError> {
79 self.convert_and_insert(id, octets, resources)
80 .map_err(LoadError::from)
81 }
82
83 fn asset_type_id(&self) -> TypeId {
84 TypeId::of::<T::AssetType>()
85 }
86}
87
88#[derive(Resource)]
89pub struct WrappedAssetLoaderRegistry {
90 pub value: Arc<Mutex<AssetLoaderRegistry>>,
91}
92
93impl Debug for WrappedAssetLoaderRegistry {
94 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
95 write!(f, "WrappedAssetLoaderRegistry")
96 }
97}
98
99#[derive(Default)]
100pub struct AssetLoaderRegistry {
101 loaders: TypeIdMap<Box<dyn AnyAssetLoader>>,
102}
103
104impl Debug for AssetLoaderRegistry {
105 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
106 write!(f, "AssetLoaderRegistry")
107 }
108}
109
110impl AssetLoaderRegistry {
111 #[must_use]
112 pub fn new() -> Self {
113 Self {
114 loaders: TypeIdMap::new(),
115 }
116 }
117
118 pub fn register_loader<T>(&mut self, loader: T)
119 where
120 T: AssetLoader + 'static,
121 {
122 debug!(
123 asset_type = type_name::<T::AssetType>(),
124 loader = type_name::<T>(),
125 "registering asset loader",
126 );
127 self.loaders
128 .insert(loader.asset_type_id(), Box::new(loader));
129 }
130
131 pub fn convert_and_insert(
134 &self,
135 id: RawWeakId,
136 octets: &[u8],
137 resources: &mut ResourceStorage,
138 ) -> Result<(), LoadError> {
139 let loader = self
140 .loaders
141 .get(&id.type_id())
142 .ok_or(LoadError::MissingLoader(id))?;
143
144 loader.convert_and_insert_erased(id, octets, resources)
145 }
146}
147
148pub struct AssetLoaderRegistryPlugin;
149
150impl Plugin for AssetLoaderRegistryPlugin {
151 fn build(&self, app: &mut App) {
152 let loader_registry = WrappedAssetLoaderRegistry {
153 value: Arc::new(Mutex::new(AssetLoaderRegistry::new())),
154 };
155 app.insert_resource(loader_registry);
156 }
157}