shader_sense/
shader_error.rs

1//! Error handling for this crate.
2use core::fmt;
3
4use crate::position::ShaderFileRange;
5
6/// Severity of a diagnostic
7#[derive(Debug, Clone, PartialEq, Eq)]
8pub enum ShaderDiagnosticSeverity {
9    Error,
10    Warning,
11    Information,
12    Hint,
13}
14impl fmt::Display for ShaderDiagnosticSeverity {
15    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
16        match self {
17            ShaderDiagnosticSeverity::Error => write!(f, "error"),
18            ShaderDiagnosticSeverity::Warning => write!(f, "warning"),
19            ShaderDiagnosticSeverity::Information => write!(f, "info"),
20            ShaderDiagnosticSeverity::Hint => write!(f, "hint"),
21        }
22    }
23}
24
25impl From<&str> for ShaderDiagnosticSeverity {
26    fn from(value: &str) -> Self {
27        match value {
28            "error" => ShaderDiagnosticSeverity::Error,
29            "warning" => ShaderDiagnosticSeverity::Warning,
30            "info" => ShaderDiagnosticSeverity::Information,
31            "hint" => ShaderDiagnosticSeverity::Hint,
32            _ => ShaderDiagnosticSeverity::Error,
33        }
34    }
35}
36
37impl ShaderDiagnosticSeverity {
38    /// Is this diagnostic required
39    pub fn is_required(&self, required_severity: ShaderDiagnosticSeverity) -> bool {
40        self.get_enum_index() <= required_severity.get_enum_index()
41    }
42    fn get_enum_index(&self) -> u32 {
43        match self {
44            ShaderDiagnosticSeverity::Error => 0,
45            ShaderDiagnosticSeverity::Warning => 1,
46            ShaderDiagnosticSeverity::Information => 2,
47            ShaderDiagnosticSeverity::Hint => 3,
48        }
49    }
50}
51
52/// A diagnostic returned by validation
53#[derive(Debug, Clone)]
54pub struct ShaderDiagnostic {
55    pub severity: ShaderDiagnosticSeverity,
56    pub error: String,
57    pub range: ShaderFileRange,
58}
59/// A list of diagnostic returned by validation
60#[derive(Debug, Default, Clone)]
61pub struct ShaderDiagnosticList {
62    pub diagnostics: Vec<ShaderDiagnostic>,
63}
64
65/// A generic error enum for this crate.
66#[derive(Debug)]
67pub enum ShaderError {
68    ValidationError(String),
69    NoSymbol,
70    ParseSymbolError(String),
71    SymbolQueryError(String, ShaderFileRange),
72    IoErr(std::io::Error),
73    InternalErr(String),
74}
75
76impl ShaderError {
77    /// Convert an error into a diagnostic if its supported
78    pub fn into_diagnostic(&self, severity: ShaderDiagnosticSeverity) -> Option<ShaderDiagnostic> {
79        match self {
80            ShaderError::SymbolQueryError(message, range) => Some(ShaderDiagnostic {
81                error: format!(
82                    "Symbol Query {}, symbol provider may be impacted: {}",
83                    severity.to_string(),
84                    message
85                ),
86                severity: severity,
87                range: range.clone(),
88            }),
89            _ => None,
90        }
91    }
92}
93
94impl From<regex::Error> for ShaderError {
95    fn from(error: regex::Error) -> Self {
96        match error {
97            regex::Error::CompiledTooBig(err) => {
98                ShaderError::InternalErr(format!("Regex compile too big: {}", err))
99            }
100            regex::Error::Syntax(err) => {
101                ShaderError::InternalErr(format!("Regex syntax invalid: {}", err))
102            }
103            err => ShaderError::InternalErr(format!("Regex error: {:#?}", err)),
104        }
105    }
106}
107
108impl fmt::Display for ShaderError {
109    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
110        match self {
111            ShaderError::IoErr(err) => write!(f, "IoError: {}", err),
112            ShaderError::InternalErr(err) => write!(f, "Internal server error: {}", err),
113            ShaderError::NoSymbol => write!(f, "No symbol found"),
114            ShaderError::ParseSymbolError(err) => write!(f, "Failed to parse symbols: {}", err),
115            ShaderError::ValidationError(err) => write!(f, "Validation error: {}", err),
116            ShaderError::SymbolQueryError(err, range) => {
117                write!(f, "SymbolQueryError: {} at {:?}", err, range)
118            }
119        }
120    }
121}
122
123impl From<std::io::Error> for ShaderError {
124    fn from(err: std::io::Error) -> Self {
125        ShaderError::IoErr(err)
126    }
127}
128impl From<ShaderDiagnostic> for ShaderDiagnosticList {
129    fn from(err: ShaderDiagnostic) -> Self {
130        Self {
131            diagnostics: vec![err],
132        }
133    }
134}
135impl ShaderDiagnosticList {
136    /// Generate an empty diagnostic list
137    pub fn empty() -> Self {
138        Self {
139            diagnostics: Vec::new(),
140        }
141    }
142    /// Push a diagnostic in the list
143    pub fn push(&mut self, error: ShaderDiagnostic) {
144        self.diagnostics.push(error);
145    }
146    /// Is the diagnostic empty
147    pub fn is_empty(&self) -> bool {
148        self.diagnostics.is_empty()
149    }
150    /// Join two diagnostics.
151    pub fn join(mut lhs: ShaderDiagnosticList, rhs: ShaderDiagnosticList) -> Self {
152        lhs.diagnostics.extend(rhs.diagnostics);
153        lhs
154    }
155}