1use crate::transformer::TransformedAsset;
2use crate::{io::Writer, meta::Settings, Asset, ErasedLoadedAsset};
3use crate::{AssetLoader, Handle, LabeledAsset, UntypedHandle};
4use bevy_utils::{BoxedFuture, ConditionalSendFuture, CowArc, HashMap};
5use serde::{Deserialize, Serialize};
6use std::{borrow::Borrow, hash::Hash, ops::Deref};
7
8pub trait AssetSaver: Send + Sync + 'static {
11 type Asset: Asset;
13 type Settings: Settings + Default + Serialize + for<'a> Deserialize<'a>;
15 type OutputLoader: AssetLoader;
17 type Error: Into<Box<dyn std::error::Error + Send + Sync + 'static>>;
19
20 fn save<'a>(
23 &'a self,
24 writer: &'a mut Writer,
25 asset: SavedAsset<'a, Self::Asset>,
26 settings: &'a Self::Settings,
27 ) -> impl ConditionalSendFuture<
28 Output = Result<<Self::OutputLoader as AssetLoader>::Settings, Self::Error>,
29 >;
30}
31
32pub trait ErasedAssetSaver: Send + Sync + 'static {
34 fn save<'a>(
37 &'a self,
38 writer: &'a mut Writer,
39 asset: &'a ErasedLoadedAsset,
40 settings: &'a dyn Settings,
41 ) -> BoxedFuture<'a, Result<(), Box<dyn std::error::Error + Send + Sync + 'static>>>;
42
43 fn type_name(&self) -> &'static str;
45}
46
47impl<S: AssetSaver> ErasedAssetSaver for S {
48 fn save<'a>(
49 &'a self,
50 writer: &'a mut Writer,
51 asset: &'a ErasedLoadedAsset,
52 settings: &'a dyn Settings,
53 ) -> BoxedFuture<'a, Result<(), Box<dyn std::error::Error + Send + Sync + 'static>>> {
54 Box::pin(async move {
55 let settings = settings
56 .downcast_ref::<S::Settings>()
57 .expect("AssetLoader settings should match the loader type");
58 let saved_asset = SavedAsset::<S::Asset>::from_loaded(asset).unwrap();
59 if let Err(err) = self.save(writer, saved_asset, settings).await {
60 return Err(err.into());
61 }
62 Ok(())
63 })
64 }
65 fn type_name(&self) -> &'static str {
66 std::any::type_name::<S>()
67 }
68}
69
70pub struct SavedAsset<'a, A: Asset> {
72 value: &'a A,
73 labeled_assets: &'a HashMap<CowArc<'static, str>, LabeledAsset>,
74}
75
76impl<'a, A: Asset> Deref for SavedAsset<'a, A> {
77 type Target = A;
78
79 fn deref(&self) -> &Self::Target {
80 self.value
81 }
82}
83
84impl<'a, A: Asset> SavedAsset<'a, A> {
85 pub fn from_loaded(asset: &'a ErasedLoadedAsset) -> Option<Self> {
87 let value = asset.value.downcast_ref::<A>()?;
88 Some(SavedAsset {
89 value,
90 labeled_assets: &asset.labeled_assets,
91 })
92 }
93
94 pub fn from_transformed(asset: &'a TransformedAsset<A>) -> Self {
96 Self {
97 value: &asset.value,
98 labeled_assets: &asset.labeled_assets,
99 }
100 }
101
102 #[inline]
104 pub fn get(&self) -> &'a A {
105 self.value
106 }
107
108 pub fn get_labeled<B: Asset, Q>(&self, label: &Q) -> Option<SavedAsset<B>>
110 where
111 CowArc<'static, str>: Borrow<Q>,
112 Q: ?Sized + Hash + Eq,
113 {
114 let labeled = self.labeled_assets.get(label)?;
115 let value = labeled.asset.value.downcast_ref::<B>()?;
116 Some(SavedAsset {
117 value,
118 labeled_assets: &labeled.asset.labeled_assets,
119 })
120 }
121
122 pub fn get_erased_labeled<Q>(&self, label: &Q) -> Option<&ErasedLoadedAsset>
124 where
125 CowArc<'static, str>: Borrow<Q>,
126 Q: ?Sized + Hash + Eq,
127 {
128 let labeled = self.labeled_assets.get(label)?;
129 Some(&labeled.asset)
130 }
131
132 pub fn get_untyped_handle<Q>(&self, label: &Q) -> Option<UntypedHandle>
134 where
135 CowArc<'static, str>: Borrow<Q>,
136 Q: ?Sized + Hash + Eq,
137 {
138 let labeled = self.labeled_assets.get(label)?;
139 Some(labeled.handle.clone())
140 }
141
142 pub fn get_handle<Q, B: Asset>(&self, label: &Q) -> Option<Handle<B>>
144 where
145 CowArc<'static, str>: Borrow<Q>,
146 Q: ?Sized + Hash + Eq,
147 {
148 let labeled = self.labeled_assets.get(label)?;
149 if let Ok(handle) = labeled.handle.clone().try_typed::<B>() {
150 return Some(handle);
151 }
152 None
153 }
154
155 pub fn iter_labels(&self) -> impl Iterator<Item = &str> {
157 self.labeled_assets.keys().map(|s| &**s)
158 }
159}