use crate::error::FilterError;
use crate::message::CanMessage;
use super::MessageFilter;
pub struct FilterChain {
filters: Vec<Box<dyn MessageFilter>>,
max_hardware_filters: usize,
hardware_filter_count: usize,
}
impl FilterChain {
#[must_use]
pub fn new(max_hardware_filters: usize) -> Self {
Self {
filters: Vec::new(),
max_hardware_filters,
hardware_filter_count: 0,
}
}
pub fn add_filter(&mut self, filter: Box<dyn MessageFilter>) {
if filter.is_hardware() && self.hardware_filter_count < self.max_hardware_filters {
self.hardware_filter_count += 1;
}
self.filters.push(filter);
}
pub fn remove_filter(&mut self, index: usize) -> Result<Box<dyn MessageFilter>, FilterError> {
if index >= self.filters.len() {
return Err(FilterError::FilterNotFound { index });
}
let filter = self.filters.remove(index);
if filter.is_hardware() && self.hardware_filter_count > 0 {
self.hardware_filter_count -= 1;
}
Ok(filter)
}
pub fn clear(&mut self) {
self.filters.clear();
self.hardware_filter_count = 0;
}
#[must_use]
pub fn matches(&self, message: &CanMessage) -> bool {
if self.filters.is_empty() {
return true;
}
self.filters.iter().any(|f| f.matches(message))
}
#[must_use]
pub fn len(&self) -> usize {
self.filters.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.filters.is_empty()
}
#[must_use]
pub fn hardware_filter_count(&self) -> usize {
self.hardware_filter_count
}
#[must_use]
pub fn software_filter_count(&self) -> usize {
self.filters
.iter()
.filter(|f| !f.is_hardware() || self.hardware_filter_count >= self.max_hardware_filters)
.count()
}
#[must_use]
pub fn max_hardware_filters(&self) -> usize {
self.max_hardware_filters
}
#[must_use]
pub fn has_hardware_capacity(&self) -> bool {
self.hardware_filter_count < self.max_hardware_filters
}
#[must_use]
pub fn total_filter_count(&self) -> usize {
self.len()
}
pub fn iter(&self) -> impl Iterator<Item = &dyn MessageFilter> {
self.filters.iter().map(std::convert::AsRef::as_ref)
}
}
impl Default for FilterChain {
fn default() -> Self {
Self::new(4) }
}
#[cfg(test)]
mod tests {
use super::*;
use crate::filter::{IdFilter, RangeFilter};
use crate::message::CanMessage;
fn make_message(id: u16) -> CanMessage {
CanMessage::new_standard(id, &[0u8; 8]).unwrap()
}
#[test]
fn test_empty_chain_passes_all() {
let chain = FilterChain::new(4);
assert!(chain.matches(&make_message(0x123)));
assert!(chain.matches(&make_message(0x456)));
}
#[test]
fn test_single_filter() {
let mut chain = FilterChain::new(4);
chain.add_filter(Box::new(IdFilter::new(0x123)));
assert!(chain.matches(&make_message(0x123)));
assert!(!chain.matches(&make_message(0x456)));
}
#[test]
fn test_multiple_filters_or_logic() {
let mut chain = FilterChain::new(4);
chain.add_filter(Box::new(IdFilter::new(0x123)));
chain.add_filter(Box::new(IdFilter::new(0x456)));
assert!(chain.matches(&make_message(0x123)));
assert!(chain.matches(&make_message(0x456)));
assert!(!chain.matches(&make_message(0x789)));
}
#[test]
fn test_mixed_filters() {
let mut chain = FilterChain::new(4);
chain.add_filter(Box::new(IdFilter::new(0x123)));
chain.add_filter(Box::new(RangeFilter::new(0x200, 0x2FF)));
assert!(chain.matches(&make_message(0x123)));
assert!(chain.matches(&make_message(0x250)));
assert!(!chain.matches(&make_message(0x300)));
}
#[test]
fn test_hardware_filter_count() {
let mut chain = FilterChain::new(2);
chain.add_filter(Box::new(IdFilter::new(0x100)));
assert_eq!(chain.hardware_filter_count(), 1);
chain.add_filter(Box::new(IdFilter::new(0x200)));
assert_eq!(chain.hardware_filter_count(), 2);
chain.add_filter(Box::new(RangeFilter::new(0x300, 0x3FF)));
assert_eq!(chain.hardware_filter_count(), 2);
}
#[test]
fn test_remove_filter() {
let mut chain = FilterChain::new(4);
chain.add_filter(Box::new(IdFilter::new(0x123)));
chain.add_filter(Box::new(IdFilter::new(0x456)));
assert_eq!(chain.len(), 2);
chain.remove_filter(0).unwrap();
assert_eq!(chain.len(), 1);
assert!(!chain.matches(&make_message(0x123)));
assert!(chain.matches(&make_message(0x456)));
}
#[test]
fn test_remove_invalid_index() {
let mut chain = FilterChain::new(4);
let result = chain.remove_filter(0);
assert!(result.is_err());
}
#[test]
fn test_clear() {
let mut chain = FilterChain::new(4);
chain.add_filter(Box::new(IdFilter::new(0x123)));
chain.add_filter(Box::new(IdFilter::new(0x456)));
chain.clear();
assert!(chain.is_empty());
assert_eq!(chain.hardware_filter_count(), 0);
}
}