notan_app/assets/
manager.rs

1use super::asset::Asset;
2use super::list::AssetList;
3use super::loader::*;
4use super::storage::AssetStorage;
5use super::utils::DoneSignal;
6
7use hashbrown::HashMap;
8use std::any::TypeId;
9use std::path::Path;
10use std::rc::Rc;
11
12#[cfg(feature = "drop_files")]
13use crate::DroppedFile;
14
15pub struct Assets {
16    storage: AssetStorage,
17    pub(crate) loaders: HashMap<String, LoaderCallback>,
18    byte_loader: LoaderCallback,
19}
20
21impl Assets {
22    pub(crate) fn new() -> Self {
23        let bytes_id = TypeId::of::<Vec<u8>>();
24        let byte_loader = LoaderCallback::Basic(
25            Some(bytes_id),
26            Rc::new(|storage, id, bytes| storage.parse::<Vec<u8>>(id, bytes)),
27        );
28
29        Self {
30            loaders: HashMap::new(),
31            storage: AssetStorage::default(),
32            byte_loader,
33        }
34    }
35
36    pub(crate) fn tick<S>(&mut self, mut params: LoaderParams<S>) -> Result<(), String> {
37        if let Some(mut to_update) = self.storage.try_load() {
38            while let Some((id, data)) = to_update.pop() {
39                let ext = Path::new(&id)
40                    .extension()
41                    .map(|ext| ext.to_str().unwrap())
42                    .unwrap_or("");
43
44                let loader = match self.loaders.get(ext) {
45                    Some(loader) => loader,
46                    None => {
47                        log::warn!("Not found a loader for '{id}', loading as bytes (Vec<u8>)");
48                        &self.byte_loader
49                    }
50                };
51
52                loader.exec(&id, data, &mut self.storage, &mut params)?;
53                self.storage.clean_asset(&id)?;
54            }
55
56            self.storage.clean_ready_assets();
57        }
58
59        Ok(())
60    }
61
62    pub fn add_loader(&mut self, loader: AssetLoader) {
63        if let Err(e) = loader.apply(self) {
64            log::error!("{e}");
65        }
66    }
67
68    fn load(&mut self, id: &str) -> Result<DoneSignal, String> {
69        let ext = Path::new(id)
70            .extension()
71            .map(|ext| ext.to_str().unwrap())
72            .unwrap_or("");
73
74        let loader = match self.loaders.get(ext) {
75            Some(loader) => loader,
76            None => {
77                log::warn!("Not found a loader for '{id}', loading as bytes (Vec<u8>)");
78                &self.byte_loader
79            }
80        };
81
82        Ok(match loader.type_id() {
83            Some(type_id) => self.storage.register(id, type_id),
84            None => return Err("Loader without output type id".to_string()),
85        })
86    }
87
88    #[cfg(all(target_arch = "wasm32", feature = "drop_files"))]
89    fn load_wasm_dropped_file(&mut self, file: &DroppedFile) -> Result<DoneSignal, String> {
90        let id = file.name.clone();
91        let ext = Path::new(&id)
92            .extension()
93            .map(|ext| ext.to_str().unwrap())
94            .unwrap_or("");
95
96        let loader = match self.loaders.get(ext) {
97            Some(loader) => loader,
98            None => {
99                log::warn!(
100                    "Not found a loader for '{}', loading as bytes (Vec<u8>)",
101                    id
102                );
103                &self.byte_loader
104            }
105        };
106
107        Ok(match loader.type_id() {
108            Some(type_id) => self
109                .storage
110                .register_wasm_dropped_file(&id, file, type_id)?,
111            None => return Err("Loader without output type id".to_string()),
112        })
113    }
114
115    pub fn load_asset<A>(&mut self, id: &str) -> Result<Asset<A>, String>
116    where
117        A: Send + Sync + 'static,
118    {
119        let _ = self.load(id)?;
120        self.storage.get(id, true)
121    }
122
123    #[cfg(all(target_arch = "wasm32", feature = "drop_files"))]
124    fn load_wasm_dropped_file_asset<A>(&mut self, file: &DroppedFile) -> Result<Asset<A>, String>
125    where
126        A: Send + Sync + 'static,
127    {
128        let _ = self.load_wasm_dropped_file(file)?;
129        self.storage.get(&file.name, true)
130    }
131
132    pub fn load_list(&mut self, paths: &[&str]) -> Result<AssetList, String> {
133        let mut list = AssetList::new(self.storage.tracker.clone());
134        for id in paths {
135            let loaded = self.load(id)?;
136            list.insert(id, loaded);
137        }
138        Ok(list)
139    }
140
141    #[cfg(feature = "drop_files")]
142    pub fn load_dropped_file<A>(&mut self, file: &DroppedFile) -> Result<Asset<A>, String>
143    where
144        A: Send + Sync + 'static,
145    {
146        if let Some(path) = &file.path {
147            if let Some(id) = path.to_str() {
148                return self.load_asset(id);
149            }
150        }
151
152        #[cfg(target_arch = "wasm32")]
153        {
154            self.load_wasm_dropped_file_asset(file)
155        }
156
157        #[cfg(not(target_arch = "wasm32"))]
158        Err(format!("Can't load the dropped file {}", file.name))
159    }
160}