1use crate::renderer::api::core::ShaderModuleId;
18use crate::renderer::api::pipeline::RenderPipelineId;
19use std::fmt;
20
21#[derive(Debug)]
23pub enum ShaderError {
24 LoadError {
26 path: String,
28 source_error: String,
30 },
31 CompilationError {
33 label: String,
35 details: String,
37 },
38 NotFound {
40 id: ShaderModuleId,
42 },
43 InvalidEntryPoint {
45 id: ShaderModuleId,
47 entry_point: String,
49 },
50}
51
52impl fmt::Display for ShaderError {
53 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
54 match self {
55 ShaderError::LoadError { path, source_error } => {
56 write!(
57 f,
58 "Failed to load shader source from '{path}': {source_error}"
59 )
60 }
61 ShaderError::CompilationError { label, details } => {
62 write!(f, "Shader compilation failed for '{label}': {details}")
63 }
64 ShaderError::NotFound { id } => {
65 write!(f, "Shader module not found for ID: {id:?}")
66 }
67 ShaderError::InvalidEntryPoint { id, entry_point } => {
68 write!(
69 f,
70 "Invalid entry point '{entry_point}' for shader module {id:?}"
71 )
72 }
73 }
74 }
75}
76
77impl std::error::Error for ShaderError {}
78
79#[derive(Debug)]
81pub enum PipelineError {
82 LayoutCreationFailed(String),
84 CompilationFailed {
86 label: Option<String>,
88 details: String,
90 },
91 InvalidShaderModuleForPipeline {
93 id: ShaderModuleId,
95 pipeline_label: Option<String>,
97 },
98 InvalidRenderPipeline {
100 id: RenderPipelineId,
102 },
103 MissingEntryPointForFragmentShader {
105 pipeline_label: Option<String>,
107 shader_id: ShaderModuleId,
109 },
110 IncompatibleColorTarget(String),
112 IncompatibleDepthStencilFormat(String),
114 FeatureNotSupported(String),
116}
117
118impl fmt::Display for PipelineError {
119 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
120 match self {
121 PipelineError::LayoutCreationFailed(msg) => {
122 write!(f, "Pipeline layout creation failed: {msg}")
123 }
124 PipelineError::CompilationFailed { label, details } => {
125 write!(
126 f,
127 "Pipeline compilation failed for '{}': {}",
128 label.as_deref().unwrap_or("Unknown"),
129 details
130 )
131 }
132 PipelineError::InvalidShaderModuleForPipeline { id, pipeline_label } => {
133 write!(
134 f,
135 "Invalid shader module {:?} for pipeline '{}'",
136 id,
137 pipeline_label.as_deref().unwrap_or("Unknown")
138 )
139 }
140 PipelineError::InvalidRenderPipeline { id } => {
141 write!(f, "Invalid render pipeline ID: {id:?}")
142 }
143 PipelineError::MissingEntryPointForFragmentShader {
144 pipeline_label,
145 shader_id,
146 } => {
147 write!(
148 f,
149 "Missing entry point for fragment shader in pipeline '{}', shader ID: {:?}",
150 pipeline_label.as_deref().unwrap_or("Unknown"),
151 shader_id
152 )
153 }
154 PipelineError::IncompatibleColorTarget(msg) => {
155 write!(f, "Incompatible color target format: {msg}")
156 }
157 PipelineError::IncompatibleDepthStencilFormat(msg) => {
158 write!(f, "Incompatible depth/stencil format: {msg}")
159 }
160 PipelineError::FeatureNotSupported(msg) => {
161 write!(f, "Feature not supported: {msg}")
162 }
163 }
164 }
165}
166
167impl std::error::Error for PipelineError {}
168
169#[derive(Debug)]
171pub enum ResourceError {
172 Shader(ShaderError),
174 Pipeline(PipelineError),
176 NotFound,
178 InvalidHandle,
180 BackendError(String),
182 OutOfBounds,
184}
185
186impl fmt::Display for ResourceError {
187 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
188 match self {
189 ResourceError::Shader(err) => write!(f, "Shader resource error: {err}"),
190 ResourceError::Pipeline(err) => write!(f, "Pipeline resource error: {err}"),
191 ResourceError::NotFound => write!(f, "Resource not found with ID."),
192 ResourceError::InvalidHandle => write!(f, "Invalid resource handle or ID."),
193 ResourceError::BackendError(msg) => {
194 write!(f, "Backend-specific resource error: {msg}")
195 }
196 ResourceError::OutOfBounds => {
197 write!(f, "Resource access out of bounds.")
198 }
199 }
200 }
201}
202
203impl std::error::Error for ResourceError {
204 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
205 match self {
206 ResourceError::Shader(err) => Some(err),
207 _ => None,
208 }
209 }
210}
211
212impl From<ShaderError> for ResourceError {
213 fn from(err: ShaderError) -> Self {
214 ResourceError::Shader(err)
215 }
216}
217
218impl From<PipelineError> for ResourceError {
219 fn from(err: PipelineError) -> Self {
220 ResourceError::Pipeline(err)
221 }
222}
223
224#[derive(Debug)]
226pub enum RenderError {
227 NotInitialized,
229 InitializationFailed(String),
231 SurfaceAcquisitionFailed(String),
233 RenderingFailed(String),
235 ResourceError(ResourceError),
237 DeviceLost,
240 Internal(String),
242}
243
244impl fmt::Display for RenderError {
245 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
246 match self {
247 RenderError::NotInitialized => {
248 write!(f, "The rendering system is not initialized.")
249 }
250 RenderError::InitializationFailed(msg) => {
251 write!(f, "Failed to initialize graphics backend: {msg}")
252 }
253 RenderError::SurfaceAcquisitionFailed(msg) => {
254 write!(f, "Failed to acquire surface for rendering: {msg}")
255 }
256 RenderError::RenderingFailed(msg) => {
257 write!(f, "A critical rendering operation failed: {msg}")
258 }
259 RenderError::ResourceError(err) => {
260 write!(f, "Graphics resource operation failed: {err}")
261 }
262 RenderError::DeviceLost => write!(
263 f,
264 "The graphics device was lost and needs to be reinitialized."
265 ),
266 RenderError::Internal(msg) => {
267 write!(f, "An internal or unexpected error occurred: {msg}")
268 }
269 }
270 }
271}
272
273impl std::error::Error for RenderError {
274 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
275 match self {
276 RenderError::ResourceError(err) => Some(err),
277 _ => None,
278 }
279 }
280}
281
282impl From<ResourceError> for RenderError {
283 fn from(err: ResourceError) -> Self {
284 RenderError::ResourceError(err)
285 }
286}
287
288#[cfg(test)]
289mod tests {
290 use std::error::Error;
291
292 use super::*;
293 use crate::renderer::api::core::ShaderModuleId;
294
295 #[test]
296 fn shader_error_display() {
297 let err = ShaderError::LoadError {
298 path: "path/to/shader.wgsl".to_string(),
299 source_error: "File not found".to_string(),
300 };
301 assert_eq!(
302 format!("{err}"),
303 "Failed to load shader source from 'path/to/shader.wgsl': File not found"
304 );
305
306 let err_comp = ShaderError::CompilationError {
307 label: "MyShader".to_string(),
308 details: "Syntax error at line 5".to_string(),
309 };
310 assert_eq!(
311 format!("{err_comp}"),
312 "Shader compilation failed for 'MyShader': Syntax error at line 5"
313 );
314 }
315
316 #[test]
317 fn resource_error_display_wrapping_shader_error() {
318 let shader_err = ShaderError::NotFound {
319 id: ShaderModuleId(42),
320 };
321 let res_err: ResourceError = shader_err.into();
322 assert_eq!(
323 format!("{res_err}"),
324 "Shader resource error: Shader module not found for ID: ShaderModuleId(42)"
325 );
326 assert!(res_err.source().is_some());
327 }
328
329 #[test]
330 fn render_error_display_wrapping_resource_error() {
331 let shader_err = ShaderError::NotFound {
332 id: ShaderModuleId(101),
333 };
334 let res_err: ResourceError = shader_err.into();
335 let render_err: RenderError = res_err.into();
336 assert_eq!(
337 format!("{render_err}"),
338 "Graphics resource operation failed: Shader resource error: Shader module not found for ID: ShaderModuleId(101)"
339 );
340 assert!(render_err.source().is_some());
341 assert!(render_err.source().unwrap().source().is_some());
342 }
343}