use super::asset::Asset;
use super::list::AssetList;
use super::loader::*;
use super::storage::AssetStorage;
use super::utils::DoneSignal;
use hashbrown::HashMap;
use std::any::TypeId;
use std::path::Path;
use std::rc::Rc;
#[cfg(feature = "drop_files")]
use crate::DroppedFile;
pub struct Assets {
storage: AssetStorage,
pub(crate) loaders: HashMap<String, LoaderCallback>,
byte_loader: LoaderCallback,
}
impl Assets {
pub(crate) fn new() -> Self {
let bytes_id = TypeId::of::<Vec<u8>>();
let byte_loader = LoaderCallback::Basic(
Some(bytes_id),
Rc::new(|storage, id, bytes| storage.parse::<Vec<u8>>(id, bytes)),
);
Self {
loaders: HashMap::new(),
storage: AssetStorage::default(),
byte_loader,
}
}
pub(crate) fn tick<S>(&mut self, mut params: LoaderParams<S>) -> Result<(), String> {
if let Some(mut to_update) = self.storage.try_load() {
while let Some((id, data)) = to_update.pop() {
let ext = Path::new(&id)
.extension()
.map(|ext| ext.to_str().unwrap())
.unwrap_or("");
let loader = match self.loaders.get(ext) {
Some(loader) => loader,
None => {
log::warn!(
"Not found a loader for '{}', loading as bytes (Vec<u8>)",
id
);
&self.byte_loader
}
};
loader.exec(&id, data, &mut self.storage, &mut params)?;
self.storage.clean_asset(&id)?;
}
self.storage.clean_ready_assets();
}
Ok(())
}
pub fn add_loader(&mut self, loader: AssetLoader) {
if let Err(e) = loader.apply(self) {
log::error!("{}", e);
}
}
fn load(&mut self, id: &str) -> Result<DoneSignal, String> {
let ext = Path::new(id)
.extension()
.map(|ext| ext.to_str().unwrap())
.unwrap_or("");
let loader = match self.loaders.get(ext) {
Some(loader) => loader,
None => {
log::warn!(
"Not found a loader for '{}', loading as bytes (Vec<u8>)",
id
);
&self.byte_loader
}
};
Ok(match loader.type_id() {
Some(type_id) => self.storage.register(id, type_id),
None => return Err("Loader without output type id".to_string()),
})
}
#[cfg(all(target_arch = "wasm32", feature = "drop_files"))]
fn load_wasm_dropped_file(&mut self, file: &DroppedFile) -> Result<DoneSignal, String> {
let id = file.name.clone();
let ext = Path::new(&id)
.extension()
.map(|ext| ext.to_str().unwrap())
.unwrap_or("");
let loader = match self.loaders.get(ext) {
Some(loader) => loader,
None => {
log::warn!(
"Not found a loader for '{}', loading as bytes (Vec<u8>)",
id
);
&self.byte_loader
}
};
Ok(match loader.type_id() {
Some(type_id) => self
.storage
.register_wasm_dropped_file(&id, file, type_id)?,
None => return Err("Loader without output type id".to_string()),
})
}
pub fn load_asset<A>(&mut self, id: &str) -> Result<Asset<A>, String>
where
A: Send + Sync + 'static,
{
let _ = self.load(id)?;
self.storage.get(id, true)
}
#[cfg(all(target_arch = "wasm32", feature = "drop_files"))]
fn load_wasm_dropped_file_asset<A>(&mut self, file: &DroppedFile) -> Result<Asset<A>, String>
where
A: Send + Sync + 'static,
{
let _ = self.load_wasm_dropped_file(file)?;
self.storage.get(&file.name, true)
}
pub fn load_list(&mut self, paths: &[&str]) -> Result<AssetList, String> {
let mut list = AssetList::new(self.storage.tracker.clone());
for id in paths {
let loaded = self.load(id)?;
list.insert(id, loaded);
}
Ok(list)
}
#[cfg(feature = "drop_files")]
pub fn load_dropped_file<A>(&mut self, file: &DroppedFile) -> Result<Asset<A>, String>
where
A: Send + Sync + 'static,
{
if let Some(path) = &file.path {
if let Some(id) = path.to_str() {
return self.load_asset(id);
}
}
#[cfg(target_arch = "wasm32")]
{
self.load_wasm_dropped_file_asset(file)
}
#[cfg(not(target_arch = "wasm32"))]
Err(format!("Can't load the dropped file {}", file.name))
}
}