use std::{error::Error, fmt}; #[derive(Clone, Debug)] pub struct ShaderError { /// The source code of the shader. pub source: String, pub label: Option, pub inner: Box, } #[cfg(feature = "wgsl-in")] impl fmt::Display for ShaderError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let label = self.label.as_deref().unwrap_or_default(); let string = self.inner.emit_to_string(&self.source); write!(f, "\nShader '{label}' parsing {string}") } } #[cfg(feature = "glsl-in")] impl fmt::Display for ShaderError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let label = self.label.as_deref().unwrap_or_default(); let string = self.inner.emit_to_string(&self.source); write!(f, "\nShader '{label}' parsing {string}") } } #[cfg(feature = "spv-in")] impl fmt::Display for ShaderError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let label = self.label.as_deref().unwrap_or_default(); let string = self.inner.emit_to_string(&self.source); write!(f, "\nShader '{label}' parsing {string}") } } impl fmt::Display for ShaderError> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use codespan_reporting::{ diagnostic::{Diagnostic, Label}, files::SimpleFile, term, }; let label = self.label.as_deref().unwrap_or_default(); let files = SimpleFile::new(label, &self.source); let config = term::Config::default(); let mut writer = term::termcolor::NoColor::new(Vec::new()); let diagnostic = Diagnostic::error().with_labels( self.inner .spans() .map(|&(span, ref desc)| { Label::primary((), span.to_range().unwrap()).with_message(desc.to_owned()) }) .collect(), ); term::emit(&mut writer, &config, &files, &diagnostic).expect("cannot write error"); write!( f, "\nShader validation {}", String::from_utf8_lossy(&writer.into_inner()) ) } } impl Error for ShaderError where ShaderError: fmt::Display, E: Error + 'static, { fn source(&self) -> Option<&(dyn Error + 'static)> { Some(&self.inner) } }