use super::{AdapterSnapshot, AddressFetcher, FetchError};
use regex::Regex;
pub trait AdapterFilter: Send + Sync {
fn matches(&self, adapter: &AdapterSnapshot) -> bool;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FilterMode {
Include,
Exclude,
}
#[derive(Debug)]
pub struct NameRegexFilter {
pattern: Regex,
mode: FilterMode,
}
impl NameRegexFilter {
pub fn new(pattern: &str, mode: FilterMode) -> Result<Self, regex::Error> {
Ok(Self {
pattern: Regex::new(pattern)?,
mode,
})
}
pub fn include(pattern: &str) -> Result<Self, regex::Error> {
Self::new(pattern, FilterMode::Include)
}
pub fn exclude(pattern: &str) -> Result<Self, regex::Error> {
Self::new(pattern, FilterMode::Exclude)
}
#[must_use]
pub const fn mode(&self) -> FilterMode {
self.mode
}
#[must_use]
#[allow(clippy::missing_const_for_fn)] pub fn pattern(&self) -> &Regex {
&self.pattern
}
}
impl AdapterFilter for NameRegexFilter {
fn matches(&self, adapter: &AdapterSnapshot) -> bool {
let is_match = self.pattern.is_match(&adapter.name);
match self.mode {
FilterMode::Include => is_match,
FilterMode::Exclude => !is_match,
}
}
}
#[derive(Debug, Clone, Copy, Default)]
pub struct ExcludeVirtualFilter;
impl AdapterFilter for ExcludeVirtualFilter {
fn matches(&self, adapter: &AdapterSnapshot) -> bool {
!adapter.kind.is_virtual()
}
}
#[derive(Debug, Clone, Copy, Default)]
pub struct ExcludeLoopbackFilter;
impl AdapterFilter for ExcludeLoopbackFilter {
fn matches(&self, adapter: &AdapterSnapshot) -> bool {
!adapter.kind.is_loopback()
}
}
#[derive(Default)]
pub struct CompositeFilter {
filters: Vec<Box<dyn AdapterFilter>>,
}
impl CompositeFilter {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn with<F: AdapterFilter + 'static>(mut self, filter: F) -> Self {
self.filters.push(Box::new(filter));
self
}
#[must_use]
pub fn len(&self) -> usize {
self.filters.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.filters.is_empty()
}
}
impl AdapterFilter for CompositeFilter {
fn matches(&self, adapter: &AdapterSnapshot) -> bool {
self.filters.iter().all(|f| f.matches(adapter))
}
}
impl std::fmt::Debug for CompositeFilter {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("CompositeFilter")
.field("filter_count", &self.filters.len())
.finish()
}
}
#[derive(Debug)]
pub struct FilteredFetcher<F, A> {
inner: F,
filter: A,
}
impl<F, A> FilteredFetcher<F, A> {
#[must_use]
pub const fn new(inner: F, filter: A) -> Self {
Self { inner, filter }
}
pub const fn inner(&self) -> &F {
&self.inner
}
pub const fn filter(&self) -> &A {
&self.filter
}
pub fn into_inner(self) -> F {
self.inner
}
}
impl<F: AddressFetcher, A: AdapterFilter> AddressFetcher for FilteredFetcher<F, A> {
fn fetch(&self) -> Result<Vec<AdapterSnapshot>, FetchError> {
let snapshots = self.inner.fetch()?;
Ok(snapshots
.into_iter()
.filter(|adapter| self.filter.matches(adapter))
.collect())
}
}
impl<T: AdapterFilter + ?Sized> AdapterFilter for &T {
fn matches(&self, adapter: &AdapterSnapshot) -> bool {
(*self).matches(adapter)
}
}
impl AdapterFilter for Box<dyn AdapterFilter> {
fn matches(&self, adapter: &AdapterSnapshot) -> bool {
self.as_ref().matches(adapter)
}
}