goud_engine/assets/storage/entry.rs
1//! [`AssetEntry`]: individual asset entry with metadata.
2
3use crate::assets::{Asset, AssetPath, AssetState};
4
5// =============================================================================
6// AssetEntry
7// =============================================================================
8
9/// An individual asset entry in storage with metadata.
10///
11/// `AssetEntry` wraps an asset value together with its loading state,
12/// optional path association, and other metadata.
13///
14/// # Example
15///
16/// ```
17/// use goud_engine::assets::{Asset, AssetEntry, AssetState, AssetPath};
18///
19/// struct Texture { width: u32 }
20/// impl Asset for Texture {}
21///
22/// // Create a loaded entry
23/// let entry = AssetEntry::loaded(Texture { width: 256 });
24/// assert!(entry.is_loaded());
25/// assert_eq!(entry.asset().unwrap().width, 256);
26///
27/// // Create entry with path
28/// let entry = AssetEntry::with_path(
29/// Texture { width: 512 },
30/// AssetPath::new("textures/player.png"),
31/// );
32/// assert_eq!(entry.path().map(|p| p.as_str()), Some("textures/player.png"));
33/// ```
34#[derive(Debug, Clone)]
35pub struct AssetEntry<A: Asset> {
36 /// The asset data, if loaded.
37 asset: Option<A>,
38
39 /// Current loading state.
40 state: AssetState,
41
42 /// Optional path this asset was loaded from.
43 path: Option<AssetPath<'static>>,
44}
45
46impl<A: Asset> AssetEntry<A> {
47 /// Creates a new entry in the `NotLoaded` state.
48 ///
49 /// Use this when you want to reserve a handle before the asset is loaded.
50 #[inline]
51 pub fn empty() -> Self {
52 Self {
53 asset: None,
54 state: AssetState::NotLoaded,
55 path: None,
56 }
57 }
58
59 /// Creates a new entry with a loading state.
60 ///
61 /// # Arguments
62 ///
63 /// * `progress` - Initial loading progress (0.0 to 1.0)
64 #[inline]
65 pub fn loading(progress: f32) -> Self {
66 Self {
67 asset: None,
68 state: AssetState::Loading { progress },
69 path: None,
70 }
71 }
72
73 /// Creates a new entry with a loaded asset.
74 #[inline]
75 pub fn loaded(asset: A) -> Self {
76 Self {
77 asset: Some(asset),
78 state: AssetState::Loaded,
79 path: None,
80 }
81 }
82
83 /// Creates a new entry with a loaded asset and path.
84 pub fn with_path(asset: A, path: AssetPath<'static>) -> Self {
85 Self {
86 asset: Some(asset),
87 state: AssetState::Loaded,
88 path: Some(path),
89 }
90 }
91
92 /// Creates a new failed entry with an error message.
93 #[inline]
94 pub fn failed(error: impl Into<String>) -> Self {
95 Self {
96 asset: None,
97 state: AssetState::Failed {
98 error: error.into(),
99 },
100 path: None,
101 }
102 }
103
104 /// Returns a reference to the asset if loaded.
105 #[inline]
106 pub fn asset(&self) -> Option<&A> {
107 self.asset.as_ref()
108 }
109
110 /// Returns a mutable reference to the asset if loaded.
111 #[inline]
112 pub fn asset_mut(&mut self) -> Option<&mut A> {
113 self.asset.as_mut()
114 }
115
116 /// Takes the asset out of this entry, leaving `None`.
117 #[inline]
118 pub fn take_asset(&mut self) -> Option<A> {
119 let asset = self.asset.take();
120 if asset.is_some() {
121 self.state = AssetState::Unloaded;
122 }
123 asset
124 }
125
126 /// Returns a reference to the current state.
127 #[inline]
128 pub fn state(&self) -> &AssetState {
129 &self.state
130 }
131
132 /// Returns the path this asset was loaded from, if any.
133 #[inline]
134 pub fn path(&self) -> Option<&AssetPath<'static>> {
135 self.path.as_ref()
136 }
137
138 /// Sets the path for this entry.
139 #[inline]
140 pub fn set_path(&mut self, path: AssetPath<'static>) {
141 self.path = Some(path);
142 }
143
144 /// Clears the path for this entry.
145 #[inline]
146 pub fn clear_path(&mut self) {
147 self.path = None;
148 }
149
150 /// Returns `true` if the asset is fully loaded.
151 #[inline]
152 pub fn is_loaded(&self) -> bool {
153 self.state.is_ready() && self.asset.is_some()
154 }
155
156 /// Returns `true` if the asset is currently loading.
157 #[inline]
158 pub fn is_loading(&self) -> bool {
159 self.state.is_loading()
160 }
161
162 /// Returns `true` if loading failed.
163 #[inline]
164 pub fn is_failed(&self) -> bool {
165 self.state.is_failed()
166 }
167
168 /// Sets the asset and marks as loaded.
169 pub fn set_loaded(&mut self, asset: A) {
170 self.asset = Some(asset);
171 self.state = AssetState::Loaded;
172 }
173
174 /// Updates the loading progress.
175 pub fn set_progress(&mut self, progress: f32) {
176 self.state = AssetState::Loading { progress };
177 }
178
179 /// Marks the entry as failed.
180 pub fn set_failed(&mut self, error: impl Into<String>) {
181 self.asset = None;
182 self.state = AssetState::Failed {
183 error: error.into(),
184 };
185 }
186
187 /// Marks the entry as unloaded and removes the asset.
188 pub fn set_unloaded(&mut self) {
189 self.asset = None;
190 self.state = AssetState::Unloaded;
191 }
192}
193
194impl<A: Asset> Default for AssetEntry<A> {
195 #[inline]
196 fn default() -> Self {
197 Self::empty()
198 }
199}