diff options
author | Daniel <kingdread@gmx.de> | 2020-04-26 11:45:37 +0200 |
---|---|---|
committer | Daniel <kingdread@gmx.de> | 2020-04-26 11:45:37 +0200 |
commit | 13053073e3336b8e6ffefd6a056d159239550be7 (patch) | |
tree | 63544e8764b55563a48d3f9fd530b0381f42a277 /src/filters/player.rs | |
parent | 3c429432382dfad6d4ac97349c96e4a4eb292089 (diff) | |
parent | 9bbd5db2a6caae10f0ab2cf2625fbc34485a4ce9 (diff) | |
download | raidgrep-13053073e3336b8e6ffefd6a056d159239550be7.tar.gz raidgrep-13053073e3336b8e6ffefd6a056d159239550be7.tar.bz2 raidgrep-13053073e3336b8e6ffefd6a056d159239550be7.zip |
Merge branch 'new-filters'
The new filter system (includes both the internal rewrite and the
command line parsing) is now being included in master. This gives a lot
more flexibility.
Diffstat (limited to 'src/filters/player.rs')
-rw-r--r-- | src/filters/player.rs | 119 |
1 files changed, 119 insertions, 0 deletions
diff --git a/src/filters/player.rs b/src/filters/player.rs new file mode 100644 index 0000000..4daeb22 --- /dev/null +++ b/src/filters/player.rs @@ -0,0 +1,119 @@ +//! This module contains filters pertaining to a single player. +//! +//! Additionally, it provides methods to lift a player filter to a log filter with [`any`][any] and +//! [`all`][all]. +use super::{ + super::{guilds, LogResult, Player, SearchField}, + log::LogFilter, + Filter, Inclusion, +}; + +use evtclib::raw::parser::PartialEvtc; +use evtclib::{Agent, AgentName}; + +use regex::Regex; + +/// Filter type for filters that operate on single players. +pub trait PlayerFilter = Filter<Agent, Player>; + +/// Struct that lifts a [`PlayerFilter`](traitalias.PlayerFilter.html) to a +/// [`LogFilter`](../log/traitalias.LogFilter.html) by requiring all players to match. +/// +/// This struct will short-circuit once the result is known. +#[derive(Debug)] +struct AllPlayers(Box<dyn PlayerFilter>); + +impl Filter<PartialEvtc, LogResult> for AllPlayers { + fn filter_early(&self, partial_evtc: &PartialEvtc) -> Inclusion { + let mut result = Inclusion::Include; + for agent in &partial_evtc.agents { + if !agent.is_player() { + continue; + } + + let agent = Agent::from_raw(agent); + if let Ok(agent) = agent { + result = result & self.0.filter_early(&agent); + } else { + result = result & Inclusion::Unknown; + } + // Short circuit + if result == Inclusion::Exclude { + return result; + } + } + result + } + + fn filter(&self, log: &LogResult) -> bool { + log.players.iter().all(|p| self.0.filter(p)) + } +} + +/// Construct a filter that requires the given `player_filter` to match for all players in a log. +pub fn all(player_filter: Box<dyn PlayerFilter>) -> Box<dyn LogFilter> { + Box::new(AllPlayers(player_filter)) +} + +/// Construct a filter that requires the given `player_filter` to match for any player in a log. +pub fn any(player_filter: Box<dyn PlayerFilter>) -> Box<dyn LogFilter> { + !all(!player_filter) +} + +/// Filter that filters players according to their name. +/// +/// The given SearchField determines in which field something should be searched. +#[derive(Debug, Clone)] +struct NameFilter(SearchField, Regex); + +impl Filter<Agent, Player> for NameFilter { + fn filter_early(&self, agent: &Agent) -> Inclusion { + if self.0 == SearchField::Guild { + return Inclusion::Unknown; + } + + if let AgentName::Player { + ref account_name, + ref character_name, + .. + } = agent.name() + { + let field = match self.0 { + SearchField::Account => account_name, + SearchField::Character => character_name, + _ => unreachable!("We already checked for Guild earlier"), + }; + self.1.is_match(field).into() + } else { + Inclusion::Unknown + } + } + + fn filter(&self, player: &Player) -> bool { + match self.0 { + SearchField::Account => self.1.is_match(&player.account_name), + SearchField::Character => self.1.is_match(&player.character_name), + SearchField::Guild => player + .guild_id + .as_ref() + .and_then(|id| guilds::lookup(id)) + .map(|guild| self.1.is_match(guild.tag()) || self.1.is_match(guild.name())) + .unwrap_or(false), + } + } +} + +/// Construct a `PlayerFilter` that searches the given `field` with the given `regex`. +pub fn name(field: SearchField, regex: Regex) -> Box<dyn PlayerFilter> { + Box::new(NameFilter(field, regex)) +} + +/// Construct a `PlayerFilter` that searches the character name with the given `regex`. +pub fn character(regex: Regex) -> Box<dyn PlayerFilter> { + name(SearchField::Character, regex) +} + +/// Construct a `PlayerFilter` that searches the account name with the given `regex`. +pub fn account(regex: Regex) -> Box<dyn PlayerFilter> { + name(SearchField::Account, regex) +} |