goud_engine/assets/asset/asset_state.rs
1//! Loading state tracking for assets.
2
3use std::fmt;
4
5/// Loading state of an asset.
6///
7/// Tracks the lifecycle of an asset from initial request to loaded (or failed).
8/// Used by the asset server to report loading progress.
9///
10/// # State Transitions
11///
12/// ```text
13/// NotLoaded ──▶ Loading ──▶ Loaded
14/// │
15/// └──▶ Failed
16/// ```
17///
18/// # FFI Safety
19///
20/// This enum is `#[repr(u8)]` for stable, FFI-compatible representation.
21///
22/// # Example
23///
24/// ```
25/// use goud_engine::assets::AssetState;
26///
27/// let state = AssetState::Loading { progress: 0.5 };
28///
29/// match state {
30/// AssetState::Loading { progress } => {
31/// println!("Loading: {}%", progress * 100.0);
32/// }
33/// AssetState::Loaded => println!("Ready!"),
34/// AssetState::Failed { .. } => println!("Error!"),
35/// _ => {}
36/// }
37/// ```
38#[repr(u8)]
39#[derive(Debug, Clone, PartialEq, Default)]
40pub enum AssetState {
41 /// Asset has not been requested for loading.
42 #[default]
43 NotLoaded = 0,
44
45 /// Asset is currently being loaded.
46 ///
47 /// Progress is a value from 0.0 to 1.0.
48 Loading {
49 /// Loading progress (0.0 to 1.0).
50 progress: f32,
51 } = 1,
52
53 /// Asset has been successfully loaded and is ready for use.
54 Loaded = 2,
55
56 /// Asset loading failed.
57 Failed {
58 /// Error message describing the failure.
59 error: String,
60 } = 3,
61
62 /// Asset was loaded but has been unloaded from memory.
63 Unloaded = 4,
64}
65
66impl AssetState {
67 /// Returns true if the asset is ready for use.
68 ///
69 /// # Example
70 ///
71 /// ```
72 /// use goud_engine::assets::AssetState;
73 ///
74 /// assert!(AssetState::Loaded.is_ready());
75 /// assert!(!AssetState::Loading { progress: 0.5 }.is_ready());
76 /// ```
77 #[inline]
78 pub fn is_ready(&self) -> bool {
79 matches!(self, AssetState::Loaded)
80 }
81
82 /// Returns true if the asset is currently loading.
83 ///
84 /// # Example
85 ///
86 /// ```
87 /// use goud_engine::assets::AssetState;
88 ///
89 /// assert!(AssetState::Loading { progress: 0.5 }.is_loading());
90 /// assert!(!AssetState::Loaded.is_loading());
91 /// ```
92 #[inline]
93 pub fn is_loading(&self) -> bool {
94 matches!(self, AssetState::Loading { .. })
95 }
96
97 /// Returns true if asset loading failed.
98 ///
99 /// # Example
100 ///
101 /// ```
102 /// use goud_engine::assets::AssetState;
103 ///
104 /// let state = AssetState::Failed { error: "File not found".to_string() };
105 /// assert!(state.is_failed());
106 /// ```
107 #[inline]
108 pub fn is_failed(&self) -> bool {
109 matches!(self, AssetState::Failed { .. })
110 }
111
112 /// Returns the loading progress if currently loading.
113 ///
114 /// Returns `None` for non-loading states.
115 ///
116 /// # Example
117 ///
118 /// ```
119 /// use goud_engine::assets::AssetState;
120 ///
121 /// let state = AssetState::Loading { progress: 0.75 };
122 /// assert_eq!(state.progress(), Some(0.75));
123 ///
124 /// assert_eq!(AssetState::Loaded.progress(), None);
125 /// ```
126 #[inline]
127 pub fn progress(&self) -> Option<f32> {
128 match self {
129 AssetState::Loading { progress } => Some(*progress),
130 _ => None,
131 }
132 }
133
134 /// Returns the error message if loading failed.
135 ///
136 /// Returns `None` for non-failed states.
137 ///
138 /// # Example
139 ///
140 /// ```
141 /// use goud_engine::assets::AssetState;
142 ///
143 /// let state = AssetState::Failed { error: "Invalid format".to_string() };
144 /// assert_eq!(state.error(), Some("Invalid format"));
145 ///
146 /// assert_eq!(AssetState::Loaded.error(), None);
147 /// ```
148 #[inline]
149 pub fn error(&self) -> Option<&str> {
150 match self {
151 AssetState::Failed { error } => Some(error),
152 _ => None,
153 }
154 }
155
156 /// Returns the discriminant as a u8 for FFI.
157 ///
158 /// # Example
159 ///
160 /// ```
161 /// use goud_engine::assets::AssetState;
162 ///
163 /// assert_eq!(AssetState::NotLoaded.discriminant(), 0);
164 /// assert_eq!(AssetState::Loading { progress: 0.0 }.discriminant(), 1);
165 /// assert_eq!(AssetState::Loaded.discriminant(), 2);
166 /// ```
167 #[inline]
168 pub fn discriminant(&self) -> u8 {
169 match self {
170 AssetState::NotLoaded => 0,
171 AssetState::Loading { .. } => 1,
172 AssetState::Loaded => 2,
173 AssetState::Failed { .. } => 3,
174 AssetState::Unloaded => 4,
175 }
176 }
177}
178
179impl fmt::Display for AssetState {
180 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
181 match self {
182 AssetState::NotLoaded => write!(f, "NotLoaded"),
183 AssetState::Loading { progress } => write!(f, "Loading({:.0}%)", progress * 100.0),
184 AssetState::Loaded => write!(f, "Loaded"),
185 AssetState::Failed { error } => write!(f, "Failed({})", error),
186 AssetState::Unloaded => write!(f, "Unloaded"),
187 }
188 }
189}