Custom Matchers
The default ExactMatcher uses HashSet membership for O(1) exact equality
checks. For dimensions that need custom logic – CIDR matching, numeric ranges,
time-of-day restrictions – implement the Matcher trait.
The Matcher trait
#![allow(unused)]
fn main() {
use abac_rs::{Matcher, AttributeValue, AttributeType};
pub trait Matcher: Send + Sync {
fn matches(
&self,
rule_value: &AttributeValue,
request_value: &AttributeType,
request_groups: &[AttributeType],
) -> bool;
fn supports_bloom_filter(&self) -> bool { true }
}
}
IP CIDR matching
Match IP addresses against CIDR ranges:
#![allow(unused)]
fn main() {
use abac_rs::{Matcher, AttributeValue, AttributeType};
pub struct IpCidrMatcher;
impl Matcher for IpCidrMatcher {
fn matches(
&self,
rule_value: &AttributeValue,
request_value: &AttributeType,
_groups: &[AttributeType],
) -> bool {
match (rule_value, request_value) {
(AttributeValue::All, _) => true,
(AttributeValue::Specific(cidrs), AttributeType::IpAddr(ip)) => {
cidrs.iter().any(|cidr| {
if let AttributeType::IpCidr(network) = cidr {
network.contains(*ip)
} else {
false
}
})
}
_ => false,
}
}
}
}
Usage:
#![allow(unused)]
fn main() {
use ipnetwork::IpNetwork;
// Rule: allow from corporate network
let rule = AbacRule::builder("allow_corp_network")
.dimension_values("source_ip", vec![
AttributeType::IpCidr("10.0.0.0/8".parse::<IpNetwork>().unwrap()),
])
.enabled(true)
.build();
// Request with IP address
let mut request = AbacRequest::new();
request.add_attribute(
"source_ip",
AttributeType::IpAddr("10.1.2.3".parse().unwrap()),
vec![]
);
}
Numeric range matching
Match integers within a range:
#![allow(unused)]
fn main() {
pub struct NumericRangeMatcher;
impl Matcher for NumericRangeMatcher {
fn matches(
&self,
rule_value: &AttributeValue,
request_value: &AttributeType,
_groups: &[AttributeType],
) -> bool {
match (rule_value, request_value) {
(AttributeValue::All, _) => true,
(AttributeValue::Specific(ranges), AttributeType::Integer(value)) => {
ranges.iter().any(|range| {
if let AttributeType::Integer(min) = range {
*value >= *min // Simplified: actual range needs min+max
} else {
false
}
})
}
_ => false,
}
}
fn supports_bloom_filter(&self) -> bool { false }
}
}
Performance considerations
Custom matchers:
- Bypass Bloom filter optimization (return
falsefromsupports_bloom_filter) - Still benefit from LRU cache and composite index
- Evaluated sequentially for candidate rules
For best performance, use ExactMatcher when possible.