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