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