1use crate::{
5 io::Reader,
6 meta::{loader_settings_meta_transform, MetaTransform, Settings},
7 Asset, AssetLoadError, AssetPath, ErasedAssetLoader, ErasedLoadedAsset, Handle, LoadContext,
8 LoadDirectError, LoadedAsset, LoadedUntypedAsset, UntypedHandle,
9};
10use alloc::{borrow::ToOwned, boxed::Box, sync::Arc};
11use core::any::{type_name, TypeId};
12use std::path::Path;
13use tracing::error;
14
15enum ReaderRef<'a> {
17 Borrowed(&'a mut dyn Reader),
18 Boxed(Box<dyn Reader + 'a>),
19}
20
21impl ReaderRef<'_> {
22 pub fn as_mut(&mut self) -> &mut dyn Reader {
23 match self {
24 ReaderRef::Borrowed(r) => &mut **r,
25 ReaderRef::Boxed(b) => &mut **b,
26 }
27 }
28}
29
30pub struct NestedLoadBuilder<'ctx, 'builder> {
32 load_context: &'builder mut LoadContext<'ctx>,
33 meta_transform: Option<MetaTransform>,
36 override_unapproved: bool,
38}
39
40impl<'ctx, 'builder> NestedLoadBuilder<'ctx, 'builder> {
41 pub(crate) fn new(load_context: &'builder mut LoadContext<'ctx>) -> Self {
42 NestedLoadBuilder {
43 load_context,
44 meta_transform: None,
45 override_unapproved: false,
46 }
47 }
48}
49
50impl<'ctx, 'builder> NestedLoadBuilder<'ctx, 'builder> {
51 #[must_use]
62 pub fn with_settings<S: Settings>(
63 mut self,
64 settings: impl Fn(&mut S) + Send + Sync + 'static,
65 ) -> Self {
66 let new_transform = loader_settings_meta_transform(settings);
67 if let Some(prev_transform) = self.meta_transform.take() {
68 self.meta_transform = Some(Box::new(move |meta| {
69 prev_transform(meta);
70 new_transform(meta);
71 }));
72 } else {
73 self.meta_transform = Some(new_transform);
74 }
75 self
76 }
77
78 #[must_use = "the load doesn't start until LoadBuilder has been consumed"]
82 pub fn override_unapproved(mut self) -> Self {
83 self.override_unapproved = true;
84 self
85 }
86
87 pub fn load<'a, A: Asset>(self, path: impl Into<AssetPath<'a>>) -> Handle<A> {
92 self.load_internal(TypeId::of::<A>(), Some(type_name::<A>()), path.into())
96 .typed_debug_checked()
97 }
98
99 pub fn load_erased<'a>(self, type_id: TypeId, path: impl Into<AssetPath<'a>>) -> UntypedHandle {
104 self.load_internal(type_id, None, path.into())
105 }
106
107 pub fn load_untyped<'a>(self, path: impl Into<AssetPath<'a>>) -> Handle<LoadedUntypedAsset> {
113 let path = path.into().to_owned();
114 if path.path() == Path::new("") {
115 error!("Attempted to load an asset with an empty path \"{path}\"!");
116 return Handle::default();
117 }
118 let handle = if self.load_context.should_load_dependencies {
119 self.load_context
120 .asset_server
121 .load_unknown_type_with_meta_transform(
122 path,
123 self.meta_transform,
124 (),
125 self.override_unapproved,
126 )
127 } else {
128 self.load_context
129 .asset_server
130 .get_or_create_path_handle(path, self.meta_transform)
131 };
132 let index = (&handle).try_into().unwrap();
135 self.load_context.dependencies.insert(index);
136 handle
137 }
138
139 pub async fn load_value<'a, A: Asset>(
143 self,
144 path: impl Into<AssetPath<'a>>,
145 ) -> Result<LoadedAsset<A>, LoadDirectError> {
146 self.load_typed_value_internal(path.into().into_owned(), None)
147 .await
148 }
149
150 pub async fn load_erased_value<'a>(
154 self,
155 type_id: TypeId,
156 path: impl Into<AssetPath<'a>>,
157 ) -> Result<ErasedLoadedAsset, LoadDirectError> {
158 self.load_value_internal(Some(type_id), &path.into().into_owned(), None)
159 .await
160 .map(|(_, asset)| asset)
161 }
162
163 pub async fn load_untyped_value<'a>(
168 self,
169 path: impl Into<AssetPath<'a>>,
170 ) -> Result<ErasedLoadedAsset, LoadDirectError> {
171 self.load_value_internal(None, &path.into().into_owned(), None)
172 .await
173 .map(|(_, asset)| asset)
174 }
175
176 pub async fn load_value_from_reader<'a, A: Asset>(
182 self,
183 path: impl Into<AssetPath<'a>>,
184 reader: &'builder mut dyn Reader,
185 ) -> Result<LoadedAsset<A>, LoadDirectError> {
186 self.load_typed_value_internal(path.into().into_owned(), Some(reader))
187 .await
188 }
189
190 pub async fn load_erased_value_from_reader<'a>(
196 self,
197 type_id: TypeId,
198 path: impl Into<AssetPath<'a>>,
199 reader: &'builder mut dyn Reader,
200 ) -> Result<ErasedLoadedAsset, LoadDirectError> {
201 self.load_value_internal(Some(type_id), &path.into().into_owned(), Some(reader))
202 .await
203 .map(|(_, asset)| asset)
204 }
205
206 pub async fn load_untyped_value_from_reader<'a>(
213 self,
214 path: impl Into<AssetPath<'a>>,
215 reader: &'builder mut dyn Reader,
216 ) -> Result<ErasedLoadedAsset, LoadDirectError> {
217 self.load_value_internal(None, &path.into().into_owned(), Some(reader))
218 .await
219 .map(|(_, asset)| asset)
220 }
221
222 fn load_internal<'a>(
225 self,
226 type_id: TypeId,
227 type_name: Option<&str>,
228 path: AssetPath<'a>,
229 ) -> UntypedHandle {
230 let path = path.to_owned();
231 if path.path() == Path::new("") {
232 error!("Attempted to load an asset with an empty path \"{path}\"!");
233 return UntypedHandle::default_for_type(type_id);
234 }
235 let handle = if self.load_context.should_load_dependencies {
236 self.load_context.asset_server.load_with_meta_transform(
237 path,
238 type_id,
239 type_name,
240 self.meta_transform,
241 (),
242 self.override_unapproved,
243 )
244 } else {
245 self.load_context
246 .asset_server
247 .get_or_create_path_handle_erased(path, type_id, type_name, self.meta_transform)
248 };
249 let index = (&handle).try_into().unwrap();
252 self.load_context.dependencies.insert(index);
253 handle
254 }
255
256 async fn load_value_internal(
262 self,
263 type_id: Option<TypeId>,
264 path: &AssetPath<'static>,
265 reader: Option<&'builder mut dyn Reader>,
266 ) -> Result<(Arc<dyn ErasedAssetLoader>, ErasedLoadedAsset), LoadDirectError> {
267 if path.path() == Path::new("") {
268 error!("Attempted to load an asset with an empty path \"{path}\"!");
269 return Err(LoadDirectError::EmptyPath(path.clone_owned()));
270 }
271 if path.label().is_some() {
272 return Err(LoadDirectError::RequestedSubasset(path.clone()));
273 }
274 self.load_context
275 .asset_server
276 .write_infos()
277 .stats
278 .started_load_tasks += 1;
279 let (mut meta, loader, mut reader) = if let Some(reader) = reader {
280 let loader = if let Some(type_id) = type_id {
281 self.load_context
282 .asset_server
283 .get_asset_loader_with_asset_type_id(type_id)
284 .await
285 .map_err(|error| LoadDirectError::LoadError {
286 dependency: path.clone(),
287 error: error.into(),
288 })?
289 } else {
290 self.load_context
291 .asset_server
292 .get_path_asset_loader(path)
293 .await
294 .map_err(|error| LoadDirectError::LoadError {
295 dependency: path.clone(),
296 error: error.into(),
297 })?
298 };
299 let meta = loader.default_meta();
300 (meta, loader, ReaderRef::Borrowed(reader))
301 } else {
302 let (meta, loader, reader) = self
303 .load_context
304 .asset_server
305 .get_meta_loader_and_reader(path, type_id)
306 .await
307 .map_err(|error| LoadDirectError::LoadError {
308 dependency: path.clone(),
309 error,
310 })?;
311 (meta, loader, ReaderRef::Boxed(reader))
312 };
313
314 if let Some(meta_transform) = self.meta_transform {
315 meta_transform(&mut *meta);
316 }
317
318 let asset = self
319 .load_context
320 .load_direct_internal(
321 path.clone(),
322 meta.loader_settings().expect("meta corresponds to a load"),
323 &*loader,
324 reader.as_mut(),
325 meta.processed_info().as_ref(),
326 )
327 .await?;
328 Ok((loader, asset))
329 }
330
331 #[cfg_attr(
334 not(target_arch = "wasm32"),
335 expect(
336 clippy::result_large_err,
337 reason = "we need to give the user the correct error type"
338 )
339 )]
340 async fn load_typed_value_internal<A: Asset>(
341 self,
342 path: AssetPath<'static>,
343 reader: Option<&'builder mut dyn Reader>,
344 ) -> Result<LoadedAsset<A>, LoadDirectError> {
345 self.load_value_internal(Some(TypeId::of::<A>()), &path, reader)
346 .await
347 .and_then(move |(loader, untyped_asset)| {
348 untyped_asset
349 .downcast::<A>()
350 .map_err(|_| LoadDirectError::LoadError {
351 dependency: path.clone(),
352 error: AssetLoadError::RequestedHandleTypeMismatch {
353 path,
354 requested: TypeId::of::<A>(),
355 actual_asset_name: loader.asset_type_name(),
356 loader_name: loader.type_path(),
357 },
358 })
359 })
360 }
361}