use std::path::PathBuf;
use thiserror::Error;
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug, Error)]
pub enum Error {
#[error("parse error at {location}: {message}")]
Parse {
message: String,
location: String,
source_text: Option<String>,
},
#[error("failed to load rule file {path}: {source}")]
RuleFileLoad {
path: PathBuf,
#[source]
source: std::io::Error,
},
#[error("invalid regex pattern '{pattern}': {source}")]
RegexCompile {
pattern: String,
#[source]
source: regex::Error,
},
#[error("invalid pattern set: {message}")]
PatternSet {
message: String,
},
#[error("invalid IP address or network '{value}': {message}")]
InvalidIp {
value: String,
message: String,
},
#[error("unknown variable: {name}")]
UnknownVariable {
name: String,
},
#[error("unknown operator: @{name}")]
UnknownOperator {
name: String,
},
#[error("unknown transformation: t:{name}")]
UnknownTransformation {
name: String,
},
#[error("unknown action: {name}")]
UnknownAction {
name: String,
},
#[error("invalid argument for action '{action}': {message}")]
InvalidActionArgument {
action: String,
message: String,
},
#[error("rule is missing required 'id' action")]
MissingRuleId,
#[error("duplicate rule id: {id}")]
DuplicateRuleId {
id: u64,
},
#[error("incomplete rule chain: chain action without following rule")]
IncompleteChain,
#[error("failed to process URI: {message}")]
ProcessUri {
message: String,
},
#[error("failed to process request headers: {message}")]
ProcessRequestHeaders {
message: String,
},
#[error("failed to process request body: {message}")]
ProcessRequestBody {
message: String,
},
#[error("failed to process response headers: {message}")]
ProcessResponseHeaders {
message: String,
},
#[error("failed to process response body: {message}")]
ProcessResponseBody {
message: String,
},
#[error("configuration error: {message}")]
Config {
message: String,
},
#[error("internal error: {message}")]
Internal {
message: String,
},
}
impl Error {
pub fn parse(message: impl Into<String>, location: impl Into<String>) -> Self {
Self::Parse {
message: message.into(),
location: location.into(),
source_text: None,
}
}
pub fn parse_with_source(
message: impl Into<String>,
location: impl Into<String>,
source_text: impl Into<String>,
) -> Self {
Self::Parse {
message: message.into(),
location: location.into(),
source_text: Some(source_text.into()),
}
}
}
#[derive(Debug, Clone, Default)]
pub struct SourceLocation {
pub file: Option<PathBuf>,
pub line: usize,
pub column: usize,
}
impl std::fmt::Display for SourceLocation {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if let Some(ref file) = self.file {
write!(f, "{}:{}:{}", file.display(), self.line, self.column)
} else {
write!(f, "{}:{}", self.line, self.column)
}
}
}