1use std::fmt;
2
3use thiserror::Error;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10pub struct SourceLocation {
11 pub line: u32,
12 pub col: u32,
13}
14
15impl fmt::Display for SourceLocation {
16 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
17 write!(f, "{}:{}", self.line, self.col)
18 }
19}
20
21#[derive(Debug, Error)]
23#[non_exhaustive]
24pub enum SigmaParserError {
25 #[error("YAML parsing error: {0}")]
26 Yaml(#[from] serde_yaml::Error),
27
28 #[error("{}", format_with_location(.0, .1))]
29 Condition(String, Option<SourceLocation>),
30
31 #[error("Unknown modifier '{0}'")]
32 UnknownModifier(String),
33
34 #[error("Invalid field specification: {0}")]
35 InvalidFieldSpec(String),
36
37 #[error("Invalid rule: {0}")]
38 InvalidRule(String),
39
40 #[error("Missing required field '{0}'")]
41 MissingField(String),
42
43 #[error("Invalid detection: {0}")]
44 InvalidDetection(String),
45
46 #[error("Invalid correlation rule: {0}")]
47 InvalidCorrelation(String),
48
49 #[error("Invalid timespan '{0}'")]
50 InvalidTimespan(String),
51
52 #[error("Invalid value: {0}")]
53 InvalidValue(String),
54
55 #[error("Invalid collection action '{0}'")]
56 InvalidAction(String),
57
58 #[error("IO error: {0}")]
59 Io(#[from] std::io::Error),
60
61 #[error("YAML merge exceeds maximum depth ({0})")]
62 MergeTooDeep(usize),
63
64 #[error("Condition string too long ({0} bytes, max {1})")]
65 ConditionTooLong(usize, usize),
66}
67
68impl SigmaParserError {
69 pub fn location(&self) -> Option<SourceLocation> {
71 match self {
72 SigmaParserError::Condition(_, loc) => *loc,
73 _ => None,
74 }
75 }
76}
77
78fn format_with_location(msg: &str, loc: &Option<SourceLocation>) -> String {
79 match loc {
80 Some(loc) => format!("Condition parse error at {loc}: {msg}"),
81 None => format!("Condition parse error: {msg}"),
82 }
83}
84
85pub type Result<T> = std::result::Result<T, SigmaParserError>;