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!(
48                            "Not found a loader for '{}', loading as bytes (Vec<u8>)",
49                            id
50                        );
51                        &self.byte_loader
52                    }
53                };
54
55                loader.exec(&id, data, &mut self.storage, &mut params)?;
56                self.storage.clean_asset(&id)?;
57            }
58
59            self.storage.clean_ready_assets();
60        }
61
62        Ok(())
63    }
64
65    pub fn add_loader(&mut self, loader: AssetLoader) {
66        if let Err(e) = loader.apply(self) {
67            log::error!("{}", e);
68        }
69    }
70
71    fn load(&mut self, id: &str) -> Result<DoneSignal, String> {
72        let ext = Path::new(id)
73            .extension()
74            .map(|ext| ext.to_str().unwrap())
75            .unwrap_or("");
76
77        let loader = match self.loaders.get(ext) {
78            Some(loader) => loader,
79            None => {
80                log::warn!(
81                    "Not found a loader for '{}', loading as bytes (Vec<u8>)",
82                    id
83                );
84                &self.byte_loader
85            }
86        };
87
88        Ok(match loader.type_id() {
89            Some(type_id) => self.storage.register(id, type_id),
90            None => return Err("Loader without output type id".to_string()),
91        })
92    }
93
94    #[cfg(all(target_arch = "wasm32", feature = "drop_files"))]
95    fn load_wasm_dropped_file(&mut self, file: &DroppedFile) -> Result<DoneSignal, String> {
96        let id = file.name.clone();
97        let ext = Path::new(&id)
98            .extension()
99            .map(|ext| ext.to_str().unwrap())
100            .unwrap_or("");
101
102        let loader = match self.loaders.get(ext) {
103            Some(loader) => loader,
104            None => {
105                log::warn!(
106                    "Not found a loader for '{}', loading as bytes (Vec<u8>)",
107                    id
108                );
109                &self.byte_loader
110            }
111        };
112
113        Ok(match loader.type_id() {
114            Some(type_id) => self
115                .storage
116                .register_wasm_dropped_file(&id, file, type_id)?,
117            None => return Err("Loader without output type id".to_string()),
118        })
119    }
120
121    pub fn load_asset<A>(&mut self, id: &str) -> Result<Asset<A>, String>
122    where
123        A: Send + Sync + 'static,
124    {
125        let _ = self.load(id)?;
126        self.storage.get(id, true)
127    }
128
129    #[cfg(all(target_arch = "wasm32", feature = "drop_files"))]
130    fn load_wasm_dropped_file_asset<A>(&mut self, file: &DroppedFile) -> Result<Asset<A>, String>
131    where
132        A: Send + Sync + 'static,
133    {
134        let _ = self.load_wasm_dropped_file(file)?;
135        self.storage.get(&file.name, true)
136    }
137
138    pub fn load_list(&mut self, paths: &[&str]) -> Result<AssetList, String> {
139        let mut list = AssetList::new(self.storage.tracker.clone());
140        for id in paths {
141            let loaded = self.load(id)?;
142            list.insert(id, loaded);
143        }
144        Ok(list)
145    }
146
147    #[cfg(feature = "drop_files")]
148    pub fn load_dropped_file<A>(&mut self, file: &DroppedFile) -> Result<Asset<A>, String>
149    where
150        A: Send + Sync + 'static,
151    {
152        if let Some(path) = &file.path {
153            if let Some(id) = path.to_str() {
154                return self.load_asset(id);
155            }
156        }
157
158        #[cfg(target_arch = "wasm32")]
159        {
160            self.load_wasm_dropped_file_asset(file)
161        }
162
163        #[cfg(not(target_arch = "wasm32"))]
164        Err(format!("Can't load the dropped file {}", file.name))
165    }
166}