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