1use crate::{meta::Settings, Asset, ErasedLoadedAsset, Handle, LabeledAsset, UntypedHandle};
2use alloc::boxed::Box;
3use atomicow::CowArc;
4use bevy_platform::collections::HashMap;
5use bevy_reflect::TypePath;
6use bevy_tasks::ConditionalSendFuture;
7use core::{
8 borrow::Borrow,
9 convert::Infallible,
10 hash::Hash,
11 marker::PhantomData,
12 ops::{Deref, DerefMut},
13};
14use serde::{Deserialize, Serialize};
15
16pub trait AssetTransformer: TypePath + Send + Sync + 'static {
20 type AssetInput: Asset;
22 type AssetOutput: Asset;
24 type Settings: Settings + Default + Serialize + for<'a> Deserialize<'a>;
26 type Error: Into<Box<dyn core::error::Error + Send + Sync + 'static>>;
28
29 fn transform<'a>(
33 &'a self,
34 asset: TransformedAsset<Self::AssetInput>,
35 settings: &'a Self::Settings,
36 ) -> impl ConditionalSendFuture<Output = Result<TransformedAsset<Self::AssetOutput>, Self::Error>>;
37}
38
39pub struct TransformedAsset<A: Asset> {
41 pub(crate) value: A,
42 pub(crate) labeled_assets: HashMap<CowArc<'static, str>, LabeledAsset>,
43}
44
45impl<A: Asset> Deref for TransformedAsset<A> {
46 type Target = A;
47 fn deref(&self) -> &Self::Target {
48 &self.value
49 }
50}
51
52impl<A: Asset> DerefMut for TransformedAsset<A> {
53 fn deref_mut(&mut self) -> &mut Self::Target {
54 &mut self.value
55 }
56}
57
58impl<A: Asset> TransformedAsset<A> {
59 pub fn from_loaded(asset: ErasedLoadedAsset) -> Option<Self> {
61 if let Ok(value) = asset.value.downcast::<A>() {
62 return Some(TransformedAsset {
63 value: *value,
64 labeled_assets: asset.labeled_assets,
65 });
66 }
67 None
68 }
69 pub fn replace_asset<B: Asset>(self, asset: B) -> TransformedAsset<B> {
71 TransformedAsset {
72 value: asset,
73 labeled_assets: self.labeled_assets,
74 }
75 }
76 pub fn take_labeled_assets<B: Asset>(&mut self, labeled_source: TransformedAsset<B>) {
78 self.labeled_assets = labeled_source.labeled_assets;
79 }
80 #[inline]
82 pub fn get(&self) -> &A {
83 &self.value
84 }
85 #[inline]
87 pub fn get_mut(&mut self) -> &mut A {
88 &mut self.value
89 }
90 pub fn get_labeled<B: Asset, Q>(&mut self, label: &Q) -> Option<TransformedSubAsset<'_, B>>
92 where
93 CowArc<'static, str>: Borrow<Q>,
94 Q: ?Sized + Hash + Eq,
95 {
96 let labeled = self.labeled_assets.get_mut(label)?;
97 let value = labeled.asset.value.downcast_mut::<B>()?;
98 Some(TransformedSubAsset {
99 value,
100 labeled_assets: &mut labeled.asset.labeled_assets,
101 })
102 }
103 pub fn get_erased_labeled<Q>(&self, label: &Q) -> Option<&ErasedLoadedAsset>
105 where
106 CowArc<'static, str>: Borrow<Q>,
107 Q: ?Sized + Hash + Eq,
108 {
109 let labeled = self.labeled_assets.get(label)?;
110 Some(&labeled.asset)
111 }
112 pub fn get_untyped_handle<Q>(&self, label: &Q) -> Option<UntypedHandle>
114 where
115 CowArc<'static, str>: Borrow<Q>,
116 Q: ?Sized + Hash + Eq,
117 {
118 let labeled = self.labeled_assets.get(label)?;
119 Some(labeled.handle.clone())
120 }
121 pub fn get_handle<Q, B: Asset>(&self, label: &Q) -> Option<Handle<B>>
123 where
124 CowArc<'static, str>: Borrow<Q>,
125 Q: ?Sized + Hash + Eq,
126 {
127 let labeled = self.labeled_assets.get(label)?;
128 if let Ok(handle) = labeled.handle.clone().try_typed::<B>() {
129 return Some(handle);
130 }
131 None
132 }
133 pub fn insert_labeled(
135 &mut self,
136 label: impl Into<CowArc<'static, str>>,
137 handle: impl Into<UntypedHandle>,
138 asset: impl Into<ErasedLoadedAsset>,
139 ) {
140 let labeled = LabeledAsset {
141 asset: asset.into(),
142 handle: handle.into(),
143 };
144 self.labeled_assets.insert(label.into(), labeled);
145 }
146 pub fn iter_labels(&self) -> impl Iterator<Item = &str> {
148 self.labeled_assets.keys().map(|s| &**s)
149 }
150}
151
152pub struct TransformedSubAsset<'a, A: Asset> {
154 value: &'a mut A,
155 labeled_assets: &'a mut HashMap<CowArc<'static, str>, LabeledAsset>,
156}
157
158impl<'a, A: Asset> Deref for TransformedSubAsset<'a, A> {
159 type Target = A;
160 fn deref(&self) -> &Self::Target {
161 self.value
162 }
163}
164
165impl<'a, A: Asset> DerefMut for TransformedSubAsset<'a, A> {
166 fn deref_mut(&mut self) -> &mut Self::Target {
167 self.value
168 }
169}
170
171impl<'a, A: Asset> TransformedSubAsset<'a, A> {
172 pub fn from_loaded(asset: &'a mut ErasedLoadedAsset) -> Option<Self> {
174 let value = asset.value.downcast_mut::<A>()?;
175 Some(TransformedSubAsset {
176 value,
177 labeled_assets: &mut asset.labeled_assets,
178 })
179 }
180 #[inline]
182 pub fn get(&self) -> &A {
183 self.value
184 }
185 #[inline]
187 pub fn get_mut(&mut self) -> &mut A {
188 self.value
189 }
190 pub fn get_labeled<B: Asset, Q>(&mut self, label: &Q) -> Option<TransformedSubAsset<'_, B>>
192 where
193 CowArc<'static, str>: Borrow<Q>,
194 Q: ?Sized + Hash + Eq,
195 {
196 let labeled = self.labeled_assets.get_mut(label)?;
197 let value = labeled.asset.value.downcast_mut::<B>()?;
198 Some(TransformedSubAsset {
199 value,
200 labeled_assets: &mut labeled.asset.labeled_assets,
201 })
202 }
203 pub fn get_erased_labeled<Q>(&self, label: &Q) -> Option<&ErasedLoadedAsset>
205 where
206 CowArc<'static, str>: Borrow<Q>,
207 Q: ?Sized + Hash + Eq,
208 {
209 let labeled = self.labeled_assets.get(label)?;
210 Some(&labeled.asset)
211 }
212 pub fn get_untyped_handle<Q>(&self, label: &Q) -> Option<UntypedHandle>
214 where
215 CowArc<'static, str>: Borrow<Q>,
216 Q: ?Sized + Hash + Eq,
217 {
218 let labeled = self.labeled_assets.get(label)?;
219 Some(labeled.handle.clone())
220 }
221 pub fn get_handle<Q, B: Asset>(&self, label: &Q) -> Option<Handle<B>>
223 where
224 CowArc<'static, str>: Borrow<Q>,
225 Q: ?Sized + Hash + Eq,
226 {
227 let labeled = self.labeled_assets.get(label)?;
228 if let Ok(handle) = labeled.handle.clone().try_typed::<B>() {
229 return Some(handle);
230 }
231 None
232 }
233 pub fn insert_labeled(
235 &mut self,
236 label: impl Into<CowArc<'static, str>>,
237 handle: impl Into<UntypedHandle>,
238 asset: impl Into<ErasedLoadedAsset>,
239 ) {
240 let labeled = LabeledAsset {
241 asset: asset.into(),
242 handle: handle.into(),
243 };
244 self.labeled_assets.insert(label.into(), labeled);
245 }
246 pub fn iter_labels(&self) -> impl Iterator<Item = &str> {
248 self.labeled_assets.keys().map(|s| &**s)
249 }
250}
251
252#[derive(TypePath)]
254pub struct IdentityAssetTransformer<A: Asset> {
255 _phantom: PhantomData<fn(A) -> A>,
256}
257
258impl<A: Asset> IdentityAssetTransformer<A> {
259 pub const fn new() -> Self {
261 Self {
262 _phantom: PhantomData,
263 }
264 }
265}
266
267impl<A: Asset> Default for IdentityAssetTransformer<A> {
268 fn default() -> Self {
269 Self::new()
270 }
271}
272
273impl<A: Asset> AssetTransformer for IdentityAssetTransformer<A> {
274 type AssetInput = A;
275 type AssetOutput = A;
276 type Settings = ();
277 type Error = Infallible;
278
279 async fn transform<'a>(
280 &'a self,
281 asset: TransformedAsset<Self::AssetInput>,
282 _settings: &'a Self::Settings,
283 ) -> Result<TransformedAsset<Self::AssetOutput>, Self::Error> {
284 Ok(asset)
285 }
286}