1use crate::{
5 io::Reader,
6 meta::{meta_transform_settings, AssetMetaDyn, MetaTransform, Settings},
7 Asset, AssetLoadError, AssetPath, ErasedAssetLoader, ErasedLoadedAsset, Handle, LoadContext,
8 LoadDirectError, LoadedAsset, LoadedUntypedAsset,
9};
10use std::any::TypeId;
11use std::sync::Arc;
12
13enum ReaderRef<'a, 'b> {
15 Borrowed(&'a mut Reader<'b>),
16 Boxed(Box<Reader<'b>>),
17}
18
19impl<'a, 'b> ReaderRef<'a, 'b> {
20 pub fn as_mut(&mut self) -> &mut Reader {
21 match self {
22 ReaderRef::Borrowed(r) => r,
23 ReaderRef::Boxed(b) => &mut *b,
24 }
25 }
26}
27
28pub struct NestedLoader<'ctx, 'builder> {
34 load_context: &'builder mut LoadContext<'ctx>,
35 meta_transform: Option<MetaTransform>,
36 asset_type_id: Option<TypeId>,
37}
38
39impl<'ctx, 'builder> NestedLoader<'ctx, 'builder> {
40 pub(crate) fn new(
41 load_context: &'builder mut LoadContext<'ctx>,
42 ) -> NestedLoader<'ctx, 'builder> {
43 NestedLoader {
44 load_context,
45 meta_transform: None,
46 asset_type_id: None,
47 }
48 }
49
50 fn with_transform(
51 mut self,
52 transform: impl Fn(&mut dyn AssetMetaDyn) + Send + Sync + 'static,
53 ) -> Self {
54 if let Some(prev_transform) = self.meta_transform {
55 self.meta_transform = Some(Box::new(move |meta| {
56 prev_transform(meta);
57 transform(meta);
58 }));
59 } else {
60 self.meta_transform = Some(Box::new(transform));
61 }
62 self
63 }
64
65 #[must_use]
70 pub fn with_settings<S: Settings>(
71 self,
72 settings: impl Fn(&mut S) + Send + Sync + 'static,
73 ) -> Self {
74 self.with_transform(move |meta| meta_transform_settings(meta, &settings))
75 }
76
77 #[must_use]
79 pub fn with_asset_type<A: Asset>(mut self) -> Self {
80 self.asset_type_id = Some(TypeId::of::<A>());
81 self
82 }
83
84 #[must_use]
86 pub fn with_asset_type_id(mut self, asset_type_id: TypeId) -> Self {
87 self.asset_type_id = Some(asset_type_id);
88 self
89 }
90
91 #[must_use]
93 pub fn direct<'c>(self) -> DirectNestedLoader<'ctx, 'builder, 'c> {
94 DirectNestedLoader {
95 base: self,
96 reader: None,
97 }
98 }
99
100 #[must_use]
105 pub fn untyped(self) -> UntypedNestedLoader<'ctx, 'builder> {
106 UntypedNestedLoader { base: self }
107 }
108
109 pub fn load<'c, A: Asset>(self, path: impl Into<AssetPath<'c>>) -> Handle<A> {
116 let path = path.into().to_owned();
117 let handle = if self.load_context.should_load_dependencies {
118 self.load_context
119 .asset_server
120 .load_with_meta_transform(path, self.meta_transform, ())
121 } else {
122 self.load_context
123 .asset_server
124 .get_or_create_path_handle(path, None)
125 };
126 self.load_context.dependencies.insert(handle.id().untyped());
127 handle
128 }
129}
130
131pub struct UntypedNestedLoader<'ctx, 'builder> {
137 base: NestedLoader<'ctx, 'builder>,
138}
139
140impl<'ctx, 'builder> UntypedNestedLoader<'ctx, 'builder> {
141 pub fn load<'p>(self, path: impl Into<AssetPath<'p>>) -> Handle<LoadedUntypedAsset> {
143 let path = path.into().to_owned();
144 let handle = if self.base.load_context.should_load_dependencies {
145 self.base
146 .load_context
147 .asset_server
148 .load_untyped_with_meta_transform(path, self.base.meta_transform)
149 } else {
150 self.base
151 .load_context
152 .asset_server
153 .get_or_create_path_handle(path, self.base.meta_transform)
154 };
155 self.base
156 .load_context
157 .dependencies
158 .insert(handle.id().untyped());
159 handle
160 }
161}
162
163pub struct DirectNestedLoader<'ctx, 'builder, 'reader> {
170 base: NestedLoader<'ctx, 'builder>,
171 reader: Option<&'builder mut Reader<'reader>>,
172}
173
174impl<'ctx: 'reader, 'builder, 'reader> DirectNestedLoader<'ctx, 'builder, 'reader> {
175 #[must_use]
177 pub fn with_reader(mut self, reader: &'builder mut Reader<'reader>) -> Self {
178 self.reader = Some(reader);
179 self
180 }
181
182 #[must_use]
187 pub fn untyped(self) -> UntypedDirectNestedLoader<'ctx, 'builder, 'reader> {
188 UntypedDirectNestedLoader { base: self }
189 }
190
191 async fn load_internal(
192 self,
193 path: &AssetPath<'static>,
194 ) -> Result<(Arc<dyn ErasedAssetLoader>, ErasedLoadedAsset), LoadDirectError> {
195 let (mut meta, loader, mut reader) = if let Some(reader) = self.reader {
196 let loader = if let Some(asset_type_id) = self.base.asset_type_id {
197 self.base
198 .load_context
199 .asset_server
200 .get_asset_loader_with_asset_type_id(asset_type_id)
201 .await
202 .map_err(|error| LoadDirectError {
203 dependency: path.clone(),
204 error: error.into(),
205 })?
206 } else {
207 self.base
208 .load_context
209 .asset_server
210 .get_path_asset_loader(path)
211 .await
212 .map_err(|error| LoadDirectError {
213 dependency: path.clone(),
214 error: error.into(),
215 })?
216 };
217 let meta = loader.default_meta();
218 (meta, loader, ReaderRef::Borrowed(reader))
219 } else {
220 let (meta, loader, reader) = self
221 .base
222 .load_context
223 .asset_server
224 .get_meta_loader_and_reader(path, self.base.asset_type_id)
225 .await
226 .map_err(|error| LoadDirectError {
227 dependency: path.clone(),
228 error,
229 })?;
230 (meta, loader, ReaderRef::Boxed(reader))
231 };
232
233 if let Some(meta_transform) = self.base.meta_transform {
234 meta_transform(&mut *meta);
235 }
236
237 let asset = self
238 .base
239 .load_context
240 .load_direct_internal(path.clone(), meta, &*loader, reader.as_mut())
241 .await?;
242 Ok((loader, asset))
243 }
244
245 pub async fn load<'p, A: Asset>(
256 mut self,
257 path: impl Into<AssetPath<'p>>,
258 ) -> Result<LoadedAsset<A>, LoadDirectError> {
259 self.base.asset_type_id = Some(TypeId::of::<A>());
260 let path = path.into().into_owned();
261 self.load_internal(&path)
262 .await
263 .and_then(move |(loader, untyped_asset)| {
264 untyped_asset.downcast::<A>().map_err(|_| LoadDirectError {
265 dependency: path.clone(),
266 error: AssetLoadError::RequestedHandleTypeMismatch {
267 path,
268 requested: TypeId::of::<A>(),
269 actual_asset_name: loader.asset_type_name(),
270 loader_name: loader.type_name(),
271 },
272 })
273 })
274 }
275}
276
277pub struct UntypedDirectNestedLoader<'ctx, 'builder, 'reader> {
284 base: DirectNestedLoader<'ctx, 'builder, 'reader>,
285}
286
287impl<'ctx: 'reader, 'builder, 'reader> UntypedDirectNestedLoader<'ctx, 'builder, 'reader> {
288 pub async fn load<'p>(
299 self,
300 path: impl Into<AssetPath<'p>>,
301 ) -> Result<ErasedLoadedAsset, LoadDirectError> {
302 let path = path.into().into_owned();
303 self.base.load_internal(&path).await.map(|(_, asset)| asset)
304 }
305}