use super::traits::{Operator, OperatorResult};
use crate::error::{Error, Result};
pub struct ContainsOperator {
needle: String,
}
impl ContainsOperator {
pub fn new(needle: &str) -> Self {
Self {
needle: needle.to_string(),
}
}
}
impl Operator for ContainsOperator {
fn execute(&self, value: &str) -> OperatorResult {
if value.contains(&self.needle) {
OperatorResult::matched(self.needle.clone())
} else {
OperatorResult::no_match()
}
}
fn name(&self) -> &'static str {
"contains"
}
}
pub struct BeginsWithOperator {
prefix: String,
}
impl BeginsWithOperator {
pub fn new(prefix: &str) -> Self {
Self {
prefix: prefix.to_string(),
}
}
}
impl Operator for BeginsWithOperator {
fn execute(&self, value: &str) -> OperatorResult {
if value.starts_with(&self.prefix) {
OperatorResult::matched(self.prefix.clone())
} else {
OperatorResult::no_match()
}
}
fn name(&self) -> &'static str {
"beginsWith"
}
}
pub struct EndsWithOperator {
suffix: String,
}
impl EndsWithOperator {
pub fn new(suffix: &str) -> Self {
Self {
suffix: suffix.to_string(),
}
}
}
impl Operator for EndsWithOperator {
fn execute(&self, value: &str) -> OperatorResult {
if value.ends_with(&self.suffix) {
OperatorResult::matched(self.suffix.clone())
} else {
OperatorResult::no_match()
}
}
fn name(&self) -> &'static str {
"endsWith"
}
}
pub struct StreqOperator {
expected: String,
}
impl StreqOperator {
pub fn new(expected: &str) -> Self {
Self {
expected: expected.to_string(),
}
}
}
impl Operator for StreqOperator {
fn execute(&self, value: &str) -> OperatorResult {
if value == self.expected {
OperatorResult::matched(value.to_string())
} else {
OperatorResult::no_match()
}
}
fn name(&self) -> &'static str {
"streq"
}
}
pub struct EqOperator {
arg: String,
}
impl EqOperator {
pub fn new(value: &str) -> Self {
Self {
arg: value.to_string(),
}
}
fn target_value(&self) -> Option<i64> {
if self.arg.contains("%{") {
return None;
}
self.arg.parse().ok()
}
}
impl Operator for EqOperator {
fn execute(&self, value: &str) -> OperatorResult {
if let Some(target) = self.target_value() {
if let Ok(n) = value.parse::<i64>() {
if n == target {
return OperatorResult::matched(value.to_string());
}
}
}
OperatorResult::no_match()
}
fn name(&self) -> &'static str {
"eq"
}
}
pub struct GtOperator {
arg: String,
}
impl GtOperator {
pub fn new(value: &str) -> Self {
Self {
arg: value.to_string(),
}
}
fn target_value(&self) -> Option<i64> {
if self.arg.contains("%{") {
return None;
}
self.arg.parse().ok()
}
}
impl Operator for GtOperator {
fn execute(&self, value: &str) -> OperatorResult {
if let Some(target) = self.target_value() {
if let Ok(n) = value.parse::<i64>() {
if n > target {
return OperatorResult::matched(value.to_string());
}
}
}
OperatorResult::no_match()
}
fn name(&self) -> &'static str {
"gt"
}
}
pub struct LtOperator {
arg: String,
}
impl LtOperator {
pub fn new(value: &str) -> Self {
Self {
arg: value.to_string(),
}
}
fn target_value(&self) -> Option<i64> {
if self.arg.contains("%{") {
return None;
}
self.arg.parse().ok()
}
}
impl Operator for LtOperator {
fn execute(&self, value: &str) -> OperatorResult {
if let Some(target) = self.target_value() {
if let Ok(n) = value.parse::<i64>() {
if n < target {
return OperatorResult::matched(value.to_string());
}
}
}
OperatorResult::no_match()
}
fn name(&self) -> &'static str {
"lt"
}
}
pub struct GeOperator {
arg: String,
}
impl GeOperator {
pub fn new(value: &str) -> Self {
Self {
arg: value.to_string(),
}
}
fn target_value(&self) -> Option<i64> {
if self.arg.contains("%{") {
return None;
}
self.arg.parse().ok()
}
}
impl Operator for GeOperator {
fn execute(&self, value: &str) -> OperatorResult {
if let Some(target) = self.target_value() {
if let Ok(n) = value.parse::<i64>() {
if n >= target {
return OperatorResult::matched(value.to_string());
}
}
}
OperatorResult::no_match()
}
fn name(&self) -> &'static str {
"ge"
}
}
pub struct LeOperator {
arg: String,
}
impl LeOperator {
pub fn new(value: &str) -> Self {
Self {
arg: value.to_string(),
}
}
fn target_value(&self) -> Option<i64> {
if self.arg.contains("%{") {
return None;
}
self.arg.parse().ok()
}
}
impl Operator for LeOperator {
fn execute(&self, value: &str) -> OperatorResult {
if let Some(target) = self.target_value() {
if let Ok(n) = value.parse::<i64>() {
if n <= target {
return OperatorResult::matched(value.to_string());
}
}
}
OperatorResult::no_match()
}
fn name(&self) -> &'static str {
"le"
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_contains() {
let op = ContainsOperator::new("admin");
assert!(op.execute("/admin/users").matched);
assert!(!op.execute("/users").matched);
}
#[test]
fn test_begins_with() {
let op = BeginsWithOperator::new("/admin");
assert!(op.execute("/admin/users").matched);
assert!(!op.execute("/users/admin").matched);
}
#[test]
fn test_ends_with() {
let op = EndsWithOperator::new(".php");
assert!(op.execute("index.php").matched);
assert!(!op.execute("index.html").matched);
}
#[test]
fn test_streq() {
let op = StreqOperator::new("admin");
assert!(op.execute("admin").matched);
assert!(!op.execute("Admin").matched);
}
#[test]
fn test_numeric_operators() {
let eq = EqOperator::new("10");
assert!(eq.execute("10").matched);
assert!(!eq.execute("11").matched);
let gt = GtOperator::new("10");
assert!(gt.execute("11").matched);
assert!(!gt.execute("10").matched);
let lt = LtOperator::new("10");
assert!(lt.execute("9").matched);
assert!(!lt.execute("10").matched);
}
}