lyra-engine/lyra-resource/src/resource_manager.rs

83 lines
2.5 KiB
Rust
Raw Normal View History

2023-09-12 18:25:33 +00:00
use std::{sync::Arc, collections::{HashMap, hash_map::DefaultHasher}, hash::{Hash, Hasher}, any::Any};
use thiserror::Error;
use crate::{resource::Resource, loader::{ResourceLoader, LoaderError, texture::TextureLoader}};
2023-09-12 18:25:33 +00:00
pub trait ResourceStorage: Send + Sync + Any + 'static {
fn as_any(&self) -> &dyn Any;
fn as_any_mut(&mut self) -> &mut dyn Any;
fn as_arc_any(self: Arc<Self>) -> Arc<dyn Any + Send + Sync>;
}
/// Implements this trait for anything that fits the type bounds
impl<T: Send + Sync + 'static> ResourceStorage for T {
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
fn as_arc_any(self: Arc<Self>) -> Arc<dyn Any + Send + Sync> {
self.clone()
}
}
#[derive(Error, Debug)]
pub enum RequestError {
#[error("{0}")]
Loader(LoaderError),
#[error("The file extension is unsupported: '{0}'")]
UnsupportedFileExtension(String),
}
impl From<LoaderError> for RequestError {
fn from(value: LoaderError) -> Self {
RequestError::Loader(value)
}
}
2023-09-12 18:25:33 +00:00
#[derive(Default)]
pub struct ResourceManager {
resources: HashMap<String, Arc<dyn ResourceStorage>>,
loaders: Vec<Box<dyn ResourceLoader>>,
2023-09-12 18:25:33 +00:00
}
impl ResourceManager {
pub fn new() -> Self {
Self {
resources: HashMap::new(),
loaders: vec![ Box::new(TextureLoader::default()) ],
2023-09-12 18:25:33 +00:00
}
}
pub fn request<T: Send + Sync + Any + 'static>(&mut self, path: &str) -> Result<Arc<Resource<T>>, RequestError> {
2023-09-12 18:25:33 +00:00
match self.resources.get(&path.to_string()) {
Some(res) => {
let res = res.clone().as_arc_any();
let res = res.downcast::<Resource<T>>().expect("Failure to downcast resource");
2023-09-12 18:25:33 +00:00
Ok(res)
2023-09-12 18:25:33 +00:00
},
None => {
if let Some(loader) = self.loaders.iter()
.find(|l| l.does_support_file(path)) {
2023-09-12 18:25:33 +00:00
// Load the resource and store it
let res = loader.load(path)?;
self.resources.insert(path.to_string(), res.clone());
2023-09-12 18:25:33 +00:00
// convert Arc<dyn ResourceStorage> to Arc<Resource<T>
let res = res.as_arc_any();
let res = res.downcast::<Resource<T>>().expect("Failure to downcast resource");
2023-09-12 18:25:33 +00:00
Ok(res)
} else {
Err(RequestError::UnsupportedFileExtension(path.to_string()))
}
2023-09-12 18:25:33 +00:00
}
}
}
}