use sequence_trie::SequenceTrie;
use witchcraft_log::{LevelFilter, Metadata};
pub struct Filter {
trie: SequenceTrie<String, LevelFilter>,
}
impl Filter {
#[inline]
pub fn builder() -> Builder {
Builder {
filter: Filter {
trie: SequenceTrie::new(),
},
root: LevelFilter::Error,
}
}
pub fn enabled(&self, metadata: &Metadata<'_>) -> bool {
metadata.level()
<= *self
.trie
.get_ancestor(metadata.target().split("::"))
.unwrap()
}
pub fn max_level(&self) -> LevelFilter {
self.trie.values().max().copied().unwrap()
}
}
pub struct Builder {
filter: Filter,
root: LevelFilter,
}
impl Builder {
#[inline]
pub fn level(mut self, level: LevelFilter) -> Self {
self.root = level;
self
}
#[inline]
pub fn target_level(mut self, target: &str, level: LevelFilter) -> Self {
self.filter.trie.insert(target.split("::"), level);
self
}
#[inline]
pub fn build(mut self) -> Filter {
self.filter.trie.insert_owned([], self.root);
self.filter
}
}
#[cfg(test)]
mod test {
use witchcraft_log::Level;
use super::*;
#[test]
fn empty() {
let filter = Filter::builder().build();
assert!(
filter.enabled(
&Metadata::builder()
.level(Level::Error)
.target("foo")
.build()
)
);
assert!(!filter.enabled(&Metadata::builder().level(Level::Warn).target("foo").build()));
}
#[test]
fn nonempty() {
let filter = Filter::builder()
.level(LevelFilter::Warn)
.target_level("foo", LevelFilter::Debug)
.target_level("foo::bar", LevelFilter::Off)
.build();
assert!(
filter.enabled(
&Metadata::builder()
.level(Level::Error)
.target("bar")
.build()
)
);
assert!(!filter.enabled(&Metadata::builder().level(Level::Info).target("bar").build()));
assert!(filter.enabled(&Metadata::builder().level(Level::Info).target("foo").build()));
assert!(
!filter.enabled(
&Metadata::builder()
.level(Level::Trace)
.target("foo")
.build()
)
);
assert!(
!filter.enabled(
&Metadata::builder()
.level(Level::Fatal)
.target("foo::bar")
.build()
)
);
assert!(
filter.enabled(
&Metadata::builder()
.level(Level::Fatal)
.target("foo::buz")
.build()
)
);
}
}