1use crate::{
24 core::uuid::Uuid, io::ResourceIo, options::BaseImportOptions, state::LoadError, ResourceData,
25};
26use fyrox_core::Downcast;
27use std::{future::Future, path::PathBuf, pin::Pin, sync::Arc};
28
29#[cfg(target_arch = "wasm32")]
30#[doc(hidden)]
31pub trait BaseResourceLoader: Downcast {}
32
33#[cfg(not(target_arch = "wasm32"))]
34#[doc(hidden)]
35pub trait BaseResourceLoader: Send + Downcast {}
36
37impl<T> BaseResourceLoader for T where T: ResourceLoader {}
38
39pub trait ResourceLoader: BaseResourceLoader {
41 fn extensions(&self) -> &[&str];
44
45 fn supports_extension(&self, ext: &str) -> bool {
47 self.extensions()
48 .iter()
49 .any(|e| fyrox_core::cmp_strings_case_insensitive(e, ext))
50 }
51
52 fn data_type_uuid(&self) -> Uuid;
54
55 fn load(&self, path: PathBuf, io: Arc<dyn ResourceIo>) -> BoxedLoaderFuture;
57
58 fn try_load_import_settings(
60 &self,
61 #[allow(unused_variables)] resource_path: PathBuf,
62 #[allow(unused_variables)] io: Arc<dyn ResourceIo>,
63 ) -> BoxedImportOptionsLoaderFuture {
64 Box::pin(async move { None })
65 }
66
67 fn default_import_options(&self) -> Option<Box<dyn BaseImportOptions>> {
69 None
70 }
71}
72
73pub struct LoaderPayload(pub(crate) Box<dyn ResourceData>);
74
75impl LoaderPayload {
76 pub fn new<T: ResourceData>(data: T) -> Self {
77 Self(Box::new(data))
78 }
79}
80
81#[cfg(target_arch = "wasm32")]
83pub type BoxedLoaderFuture = Pin<Box<dyn Future<Output = Result<LoaderPayload, LoadError>>>>;
84
85#[cfg(not(target_arch = "wasm32"))]
87pub type BoxedLoaderFuture = Pin<Box<dyn Future<Output = Result<LoaderPayload, LoadError>> + Send>>;
88
89pub type BoxedImportOptionsLoaderFuture =
91 Pin<Box<dyn Future<Output = Option<Box<dyn BaseImportOptions>>>>>;
92
93#[derive(Default)]
95pub struct ResourceLoadersContainer {
96 loaders: Vec<Box<dyn ResourceLoader>>,
97}
98
99impl ResourceLoadersContainer {
100 pub fn new() -> Self {
102 Self::default()
103 }
104
105 pub fn set<T>(&mut self, loader: T) -> Option<T>
108 where
109 T: ResourceLoader,
110 {
111 if let Some(existing_loader) = self
112 .loaders
113 .iter_mut()
114 .find_map(|l| (**l).as_any_mut().downcast_mut::<T>())
115 {
116 Some(std::mem::replace(existing_loader, loader))
117 } else {
118 self.loaders.push(Box::new(loader));
119 None
120 }
121 }
122
123 pub fn try_replace<Prev, New>(&mut self, new_loader: New) -> Option<Prev>
126 where
127 Prev: ResourceLoader,
128 New: ResourceLoader,
129 {
130 if let Some(pos) = self
131 .loaders
132 .iter()
133 .position(|l| (**l).as_any().is::<Prev>())
134 {
135 let prev_untyped = std::mem::replace(&mut self.loaders[pos], Box::new(new_loader));
136 prev_untyped
137 .into_any()
138 .downcast::<Prev>()
139 .ok()
140 .map(|boxed| *boxed)
141 } else {
142 None
143 }
144 }
145
146 pub fn find<T>(&self) -> Option<&T>
148 where
149 T: ResourceLoader,
150 {
151 self.loaders
152 .iter()
153 .find_map(|loader| (**loader).as_any().downcast_ref())
154 }
155
156 pub fn find_mut<T>(&mut self) -> Option<&mut T>
158 where
159 T: ResourceLoader,
160 {
161 self.loaders
162 .iter_mut()
163 .find_map(|loader| (**loader).as_any_mut().downcast_mut())
164 }
165
166 pub fn len(&self) -> usize {
168 self.loaders.len()
169 }
170
171 pub fn is_empty(&self) -> bool {
173 self.loaders.is_empty()
174 }
175
176 pub fn iter(&self) -> impl Iterator<Item = &dyn ResourceLoader> {
178 self.loaders.iter().map(|boxed| &**boxed)
179 }
180
181 pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut dyn ResourceLoader> {
183 self.loaders.iter_mut().map(|boxed| &mut **boxed)
184 }
185}
186
187#[cfg(test)]
188mod test {
189 use super::*;
190
191 #[derive(Eq, PartialEq, Debug)]
192 struct MyResourceLoader;
193
194 impl ResourceLoader for MyResourceLoader {
195 fn extensions(&self) -> &[&str] {
196 &[]
197 }
198
199 fn data_type_uuid(&self) -> Uuid {
200 Default::default()
201 }
202
203 fn load(&self, _path: PathBuf, _io: Arc<dyn ResourceIo>) -> BoxedLoaderFuture {
204 todo!()
205 }
206 }
207
208 #[test]
209 fn resource_loader_container_new() {
210 let container = ResourceLoadersContainer::new();
211 assert!(container.loaders.is_empty());
212
213 let container = ResourceLoadersContainer::default();
214 assert!(container.loaders.is_empty());
215 }
216
217 #[test]
218 fn resource_loader_container_set() {
219 let mut container = ResourceLoadersContainer::new();
220 let res = container.set(MyResourceLoader);
221 let res2 = container.set(MyResourceLoader);
222 assert_eq!(res, None);
223 assert_eq!(res2, Some(MyResourceLoader));
224
225 assert_eq!(container.len(), 1);
226 }
227
228 #[test]
229 fn resource_loader_container_find() {
230 let mut container = ResourceLoadersContainer::new();
231
232 let res = container.find::<MyResourceLoader>();
233 assert_eq!(res, None);
234
235 container.set(MyResourceLoader);
236 let res = container.find::<MyResourceLoader>();
237
238 assert_eq!(res, Some(&MyResourceLoader));
239 }
240
241 #[test]
242 fn resource_loader_container_find_mut() {
243 let mut container = ResourceLoadersContainer::new();
244
245 let res = container.find_mut::<MyResourceLoader>();
246 assert_eq!(res, None);
247
248 container.set(MyResourceLoader);
249 let res = container.find_mut::<MyResourceLoader>();
250
251 assert_eq!(res, Some(&mut MyResourceLoader));
252 }
253
254 #[test]
255 fn resource_loader_container_getters() {
256 let mut container = ResourceLoadersContainer::new();
257 assert!(container.is_empty());
258 assert_eq!(container.len(), 0);
259
260 container.set(MyResourceLoader);
261 container.set(MyResourceLoader);
262 assert!(!container.is_empty());
263 assert_eq!(container.len(), 1);
264 }
265}