diff options
author | Daniel <kingdread@gmx.de> | 2019-02-16 01:48:59 +0100 |
---|---|---|
committer | Daniel <kingdread@gmx.de> | 2019-02-16 01:48:59 +0100 |
commit | dfbf78622b0869f070d062b3edd40c4a97ce7dfd (patch) | |
tree | 980e0fc50f5b0e89210a0d086fb9ee87c1e73f51 /src/csl.rs | |
parent | 2fb14e9e5c5e48c3231f6d4aa324917d0dd3ccf7 (diff) | |
download | raidgrep-dfbf78622b0869f070d062b3edd40c4a97ce7dfd.tar.gz raidgrep-dfbf78622b0869f070d062b3edd40c4a97ce7dfd.tar.bz2 raidgrep-dfbf78622b0869f070d062b3edd40c4a97ce7dfd.zip |
introduce CommaSeparatedList
This gives a common interface for command line flags which take multiple
values, possibly with negation.
This might come in useful if we add filtering by boss, e.g. "--boss
!deimos" to ignore all deimos logs.
Diffstat (limited to 'src/csl.rs')
-rw-r--r-- | src/csl.rs | 92 |
1 files changed, 92 insertions, 0 deletions
diff --git a/src/csl.rs b/src/csl.rs new file mode 100644 index 0000000..83f2e14 --- /dev/null +++ b/src/csl.rs @@ -0,0 +1,92 @@ +use std::collections::HashSet; +use std::hash::Hash; +use std::str::FromStr; +use std::fmt; + +use super::{SearchField, FightOutcome}; + +pub trait Variants: Copy { + type Output: Iterator<Item=Self>; + fn variants() -> Self::Output; +} + +macro_rules! variants { + ($target:ident => $($var:ident),+) => { + impl Variants for $target { + type Output = ::std::iter::Cloned<::std::slice::Iter<'static, Self>>; + fn variants() -> Self::Output { + // Exhaustiveness check + #[allow(dead_code)] + fn exhaustiveness_check(value: $target) { + match value { + $($target :: $var => ()),+ + } + } + // Actual result + [ + $($target :: $var),+ + ].iter().cloned() + } + } + } +} + +variants! { SearchField => Account, Character } +variants! { FightOutcome => Success, Wipe } + +/// The character that delimits items from each other. +const DELIMITER: char = ','; +/// The character that negates the result. +const NEGATOR: char = '!'; + +/// A list that is given as comma-separated values. +#[derive(Debug, Clone)] +pub struct CommaSeparatedList<T: Eq + Hash + fmt::Debug> { + values: HashSet<T>, +} + +#[derive(Debug, Clone)] +pub enum ParseError<E> { + Underlying(E), +} + +impl<E: fmt::Display> fmt::Display for ParseError<E> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + ParseError::Underlying(ref e) => e.fmt(f), + } + } +} + +impl<T> FromStr for CommaSeparatedList<T> + where T: FromStr + Variants + Hash + Eq + fmt::Debug +{ + type Err = ParseError<T::Err>; + + fn from_str(input: &str) -> Result<Self, Self::Err> { + if input == "*" { + Ok(CommaSeparatedList { values: T::variants().collect() }) + } else if input.starts_with(NEGATOR) { + let no_csl = CommaSeparatedList::from_str(&input[1..])?; + let all_values = T::variants().collect::<HashSet<_>>(); + Ok(CommaSeparatedList { + values: all_values.difference(&no_csl.values).cloned().collect() + }) + } else { + let parts = input.split(DELIMITER); + let values = parts + .map(FromStr::from_str) + .collect::<Result<HashSet<_>, _>>() + .map_err(ParseError::Underlying)?; + Ok(CommaSeparatedList { values }) + } + } +} + +impl<T> CommaSeparatedList<T> + where T: Hash + Eq + fmt::Debug +{ + pub fn contains(&self, value: &T) -> bool { + self.values.contains(value) + } +} |