1use crate::loader::{Asset, ErasedAssetLoader};
2use crate::{ResourceError, ResourceResult};
3use log::debug;
4use specs::Component;
5use specs::VecStorage;
6use std::any::{Any, TypeId};
7use std::collections::HashMap;
8use std::fs::File;
9use std::io::Read;
10use std::marker::PhantomData;
11use std::ops::Deref;
12use std::path::{Path, PathBuf};
13use std::sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard};
14
15#[derive(Debug, Default)]
17pub struct AssetServer {
18 root: Option<PathBuf>,
19 loaders: HashMap<TypeId, Box<dyn ErasedAssetLoader>>,
21 caches: HashMap<TypeId, Box<dyn Any + Send + Sync>>,
23 metas: HashMap<UntypedAssetId, Metadata>,
25}
26
27#[derive(Clone, Component, Debug)]
29#[storage(VecStorage)]
30pub struct Handle<A: Asset + ?Sized> {
31 id: AssetId<A>,
32 inner: Arc<RwLock<A>>,
33}
34
35#[derive(Debug, PartialEq, Eq, Hash)]
37pub struct AssetId<A: Asset + ?Sized> {
38 raw: u32,
40 generation: u32,
41 _marker: PhantomData<fn() -> A>,
42}
43
44impl<A: Asset + ?Sized> Copy for AssetId<A> {}
45
46impl<A: Asset + ?Sized> Clone for AssetId<A> {
47 fn clone(&self) -> Self {
48 *self
49 }
50}
51
52impl<A: Asset + ?Sized> AssetId<A> {
53 pub(crate) fn new(raw: u32, generation: u32) -> Self {
54 Self {
55 raw,
56 generation,
57 _marker: PhantomData,
58 }
59 }
60
61 pub(crate) fn index(&self) -> usize {
62 self.raw as usize
63 }
64
65 #[allow(unused)]
66 pub(crate) fn raw(&self) -> u32 {
67 self.raw
68 }
69
70 pub(crate) fn generation(&self) -> u32 {
71 self.generation
72 }
73}
74
75impl<A: Asset> AssetId<A> {
76 pub(crate) fn untyped(self) -> UntypedAssetId {
77 UntypedAssetId {
78 type_id: TypeId::of::<A>(),
79 raw: self.raw,
80 generation: self.generation,
81 }
82 }
83}
84
85#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
86pub(crate) struct UntypedAssetId {
87 type_id: TypeId,
88 raw: u32,
89 generation: u32,
90}
91
92#[derive(Debug, Clone)]
93pub(crate) struct Metadata {
94 source: AssetSource,
95 _type_id: TypeId,
96}
97
98#[derive(Debug, Clone)]
99#[allow(unused)]
100pub(crate) enum AssetSource {
101 File {
102 path: PathBuf,
103 modified: std::time::SystemTime,
104 },
105 Reader,
106 Internal,
107}
108
109#[derive(Debug)]
110struct AssetSlot<A: Asset> {
111 generation: u32,
112 asset: Option<Arc<RwLock<A>>>,
113}
114
115#[derive(Debug)]
116struct AssetCache<A: Asset> {
117 assets: Vec<AssetSlot<A>>,
118 names: HashMap<String, AssetId<A>>,
119}
120
121impl<A: Asset> AssetCache<A> {
122 fn new() -> Self {
123 Self {
124 assets: Vec::new(),
125 names: HashMap::new(),
126 }
127 }
128
129 fn insert(&mut self, asset: A) -> Handle<A> {
130 let raw = self.assets.len() as u32;
131 let generation = 0;
132 let id = AssetId::new(raw, generation);
133
134 let handle = Handle::new(id, asset);
135
136 self.assets.push(AssetSlot {
137 generation,
138 asset: Some(handle.inner()),
139 });
140
141 handle
142 }
143
144 fn insert_named(&mut self, name: String, asset: A) -> Handle<A> {
145 let handle = self.insert(asset);
146 self.names.insert(name, handle.id());
147 handle
148 }
149
150 fn get(&self, id: AssetId<A>) -> Option<Handle<A>> {
151 let slot = self.assets.get(id.index())?;
152
153 if slot.generation != id.generation() {
154 return None;
155 }
156
157 let inner = slot.asset.as_ref()?.clone();
158
159 Some(Handle::from_inner(id, inner))
160 }
161
162 fn get_named(&self, name: &str) -> Option<Handle<A>> {
163 let id = self.names.get(name)?;
164 self.get(*id)
165 }
166
167 fn id_named(&self, name: &str) -> Option<AssetId<A>> {
168 self.names.get(name).copied()
169 }
170
171 fn reload(&mut self, id: AssetId<A>, new_asset: A) -> ResourceResult<()> {
172 let slot = self
173 .assets
174 .get_mut(id.index())
175 .ok_or(ResourceError::ResourceDoesNotExist)?;
176
177 if slot.generation != id.generation() {
178 return Err(ResourceError::ResourceDoesNotExist);
179 }
180
181 let existing = slot
182 .asset
183 .as_ref()
184 .ok_or(ResourceError::ResourceDoesNotExist)?;
185
186 *existing.write().expect("asset lock poisoned") = new_asset;
187
188 Ok(())
189 }
190}
191
192impl<A: Asset> Handle<A> {
193 pub fn id(&self) -> AssetId<A> {
195 self.id
196 }
197
198 pub(crate) fn new(id: AssetId<A>, asset: A) -> Self {
199 Self {
200 id,
201 inner: Arc::new(RwLock::new(asset)),
202 }
203 }
204
205 pub(crate) fn from_inner(id: AssetId<A>, inner: Arc<RwLock<A>>) -> Self {
206 Self { id, inner }
207 }
208
209 pub(crate) fn inner(&self) -> Arc<RwLock<A>> {
210 self.inner.clone()
211 }
212
213 pub fn read(&self) -> AssetRead<'_, A> {
215 AssetRead {
216 guard: self.inner.read().expect("asset lock poisoned"),
217 }
218 }
219
220 pub fn write(&self) -> AssetWrite<'_, A> {
222 AssetWrite {
223 guard: self.inner.write().expect("asset lock poisoned"),
224 }
225 }
226}
227
228impl AssetServer {
229 pub fn new() -> Self {
231 Self::default()
232 }
233
234 pub fn with_root(root: impl Into<PathBuf>) -> Self {
236 Self {
237 root: Some(root.into()),
238 ..Self::default()
239 }
240 }
241
242 pub fn register_asset_type<A: Asset>(&mut self) {
246 self.caches
247 .entry(TypeId::of::<A>())
248 .or_insert_with(|| Box::new(AssetCache::<A>::new()));
249 }
250
251 pub fn register_loader<A: Asset>(&mut self, loader: Box<dyn ErasedAssetLoader>) {
253 self.register_asset_type::<A>();
254 self.loaders.insert(TypeId::of::<A>(), loader);
255 }
256
257 pub fn load_reader<A: Asset>(
262 &mut self,
263 name: &str,
264 reader: &mut dyn Read,
265 ) -> ResourceResult<Handle<A>> {
266 let asset = self.load_asset_from_reader::<A>(reader)?;
267
268 let handle = self
269 .cache_mut::<A>()
270 .expect("asset cache was not registered")
271 .insert_named(name.to_string(), asset);
272
273 self.metas.insert(
274 handle.id().untyped(),
275 Metadata {
276 source: AssetSource::Reader,
277 _type_id: TypeId::of::<A>(),
278 },
279 );
280
281 Ok(handle)
282 }
283
284 pub fn insert<A: Asset>(&mut self, asset: A) -> ResourceResult<Handle<A>> {
286 let handle = self
287 .cache_mut::<A>()
288 .expect("asset cache was not registered")
289 .insert(asset);
290
291 self.metas.insert(
292 handle.id().untyped(),
293 Metadata {
294 source: AssetSource::Internal,
295 _type_id: TypeId::of::<A>(),
296 },
297 );
298
299 Ok(handle)
300 }
301
302 pub fn insert_named<A: Asset>(
304 &mut self,
305 name: impl Into<String>,
306 asset: A,
307 ) -> ResourceResult<Handle<A>> {
308 let handle = self
309 .cache_mut::<A>()
310 .expect("asset cache was not registered")
311 .insert_named(name.into(), asset);
312
313 self.metas.insert(
314 handle.id().untyped(),
315 Metadata {
316 source: AssetSource::Internal,
317 _type_id: TypeId::of::<A>(),
318 },
319 );
320
321 Ok(handle)
322 }
323
324 pub fn load<A: Asset>(&mut self, path: impl Into<PathBuf>) -> ResourceResult<Handle<A>> {
329 let root = self
330 .root
331 .as_ref()
332 .ok_or(ResourceError::AssetServerUnsupported)?;
333
334 let path = path.into();
335 let name = asset_name(&path)?;
336 let full_path = root.join(&path);
337
338 debug!("loading asset from {:?}", full_path);
339
340 let modified = std::fs::metadata(&full_path)?.modified()?;
341
342 let mut reader = File::open(&full_path)?;
343 let asset = self.load_asset_from_reader::<A>(&mut reader)?;
344
345 let handle = self
346 .cache_mut::<A>()
347 .expect("asset cache was not registered")
348 .insert_named(name, asset);
349
350 self.metas.insert(
351 handle.id().untyped(),
352 Metadata {
353 source: AssetSource::File {
354 path: full_path,
355 modified,
356 },
357 _type_id: TypeId::of::<A>(),
358 },
359 );
360
361 Ok(handle)
362 }
363
364 pub fn get<A: Asset>(&self, id: AssetId<A>) -> Option<Handle<A>> {
366 self.cache::<A>()?.get(id)
367 }
368
369 pub fn get_named<A: Asset>(&self, name: &str) -> Option<Handle<A>> {
371 self.cache::<A>()?.get_named(name)
372 }
373
374 pub fn id_named<A: Asset>(&self, name: &str) -> Option<AssetId<A>> {
376 self.cache::<A>()?.id_named(name)
377 }
378
379 pub fn reload<A: Asset>(&mut self, id: AssetId<A>) -> ResourceResult<()> {
381 self.root
382 .as_ref()
383 .ok_or(ResourceError::AssetServerUnsupported)?;
384
385 let source = self
386 .metas
387 .get(&id.untyped())
388 .ok_or(ResourceError::ResourceDoesNotExist)?
389 .source
390 .clone();
391
392 let AssetSource::File { path, .. } = source else {
393 return Err(ResourceError::ResourceDoesNotExist);
394 };
395
396 let mut reader = File::open(&path)?;
397 let new_asset = self.load_asset_from_reader::<A>(&mut reader)?;
398
399 self.cache_mut::<A>()
400 .expect("asset cache was not registered")
401 .reload(id, new_asset)?;
402
403 Ok(())
404 }
405
406 pub fn reload_named<A: Asset>(&mut self, name: &str) -> ResourceResult<()> {
408 let id = self
409 .id_named::<A>(name)
410 .ok_or(ResourceError::ResourceDoesNotExist)?;
411
412 self.reload(id)
413 }
414
415 fn load_asset_from_reader<A: Asset>(&self, reader: &mut dyn Read) -> ResourceResult<A> {
416 let loader = self
417 .loaders
418 .get(&TypeId::of::<A>())
419 .ok_or(ResourceError::LoaderNotFound)?;
420
421 loader
422 .load_erased(reader)?
423 .downcast::<A>()
424 .map(|asset| *asset)
425 .map_err(|_| ResourceError::LoaderReturnedWrongType)
426 }
427
428 fn cache<A: Asset>(&self) -> Option<&AssetCache<A>> {
429 self.caches
430 .get(&TypeId::of::<A>())?
431 .downcast_ref::<AssetCache<A>>()
432 }
433
434 fn cache_mut<A: Asset>(&mut self) -> Option<&mut AssetCache<A>> {
435 self.caches
436 .get_mut(&TypeId::of::<A>())?
437 .downcast_mut::<AssetCache<A>>()
438 }
439}
440
441fn asset_name(path: &Path) -> ResourceResult<String> {
442 path.with_extension("")
443 .to_str()
444 .map(ToOwned::to_owned)
445 .ok_or(ResourceError::NotFound(path.to_path_buf()))
446}
447
448pub struct AssetRead<'a, A> {
450 guard: RwLockReadGuard<'a, A>,
451}
452
453impl<A> Deref for AssetRead<'_, A> {
454 type Target = A;
455
456 fn deref(&self) -> &Self::Target {
457 &self.guard
458 }
459}
460
461pub struct AssetWrite<'a, A> {
463 guard: RwLockWriteGuard<'a, A>,
464}
465
466impl<A> Deref for AssetWrite<'_, A> {
467 type Target = A;
468
469 fn deref(&self) -> &Self::Target {
470 &self.guard
471 }
472}
473
474impl<A> std::ops::DerefMut for AssetWrite<'_, A> {
475 fn deref_mut(&mut self) -> &mut Self::Target {
476 &mut self.guard
477 }
478}