diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/main.rs | 51 | ||||
| -rw-r--r-- | src/playerclass.rs | 141 | 
2 files changed, 147 insertions, 45 deletions
| diff --git a/src/main.rs b/src/main.rs index 625e869..d9f0817 100644 --- a/src/main.rs +++ b/src/main.rs @@ -17,7 +17,7 @@ use structopt::StructOpt;  use walkdir::{DirEntry, WalkDir};  use evtclib::raw::parser::PartialEvtc; -use evtclib::{EliteSpec, EventKind, Log, Profession}; +use evtclib::{EventKind, Log};  mod fexpr;  mod filters; @@ -26,6 +26,8 @@ mod guilds;  mod logger;  mod output;  mod paths; +mod playerclass; +use playerclass::PlayerClass;  /// Application name, as it should be used in configuration directory paths.  const APP_NAME: &str = "raidgrep"; @@ -145,8 +147,8 @@ pub struct Player {      account_name: String,      /// Character name of the player.      character_name: String, -    /// Profession (or elite specialization) as english name. -    profession: String, +    /// Profession or elite specialization. +    profession: PlayerClass,      /// Subsquad that the player was in.      subgroup: u8,      /// Guild ID, ready for API consumption. @@ -478,7 +480,7 @@ fn extract_info(entry: &DirEntry, log: &Log) -> LogResult {          .map(|p| Player {              account_name: p.account_name().to_owned(),              character_name: p.character_name().to_owned(), -            profession: get_profession_name(p.profession(), p.elite()).into(), +            profession: (p.profession(), p.elite()).into(),              subgroup: p.subgroup(),              guild_id: guild_ids.get(&p.addr()).cloned(),          }) @@ -570,44 +572,3 @@ fn get_encounter_name(log: &Log) -> Option<&'static str> {          Boss::WhisperOfJormag => "Whisper of Jormag",      })  } - -/// Get the (english) name for the given profession/elite specialization. -fn get_profession_name(profession: Profession, elite: Option<EliteSpec>) -> &'static str { -    use EliteSpec::*; -    use Profession::*; - -    if let Some(elite) = elite { -        match elite { -            Dragonhunter => "Dragonhunter", -            Firebrand => "Firebrand", -            Berserker => "Berserker", -            Spellbreaker => "Spellbreaker", -            Herald => "Herald", -            Renegade => "Renegade", -            Scrapper => "Scrapper", -            Holosmith => "Holosmith", -            Druid => "Druid", -            Soulbeast => "Soulbeast", -            Daredevil => "Daredevil", -            Deadeye => "Deadeye", -            Tempest => "Tempest", -            Weaver => "Weaver", -            Chronomancer => "Chronomancer", -            Mirage => "Mirage", -            Reaper => "Reaper", -            Scourge => "Scourge", -        } -    } else { -        match profession { -            Guardian => "Guardian", -            Warrior => "Warrior", -            Revenant => "Revenant", -            Engineer => "Engineer", -            Ranger => "Ranger", -            Thief => "Thief", -            Elementalist => "Elementalist", -            Mesmer => "Mesmer", -            Necromancer => "Necromancer", -        } -    } -} diff --git a/src/playerclass.rs b/src/playerclass.rs new file mode 100644 index 0000000..77b9794 --- /dev/null +++ b/src/playerclass.rs @@ -0,0 +1,141 @@ +use std::{fmt, str::FromStr}; + +use evtclib::{EliteSpec, Profession}; + +use thiserror::Error; + +/// An enum containing either a profession or an elite spec. +/// +/// This enum provides us with a variety of things: +/// +/// Game mechanic wise, a Dragonhunter is also a Guardian, because Dragonhunter is only the elite +/// specialization. However, when outputting that to the user, we usually only write Dragonhunter, +/// and not Guardian, as that is implied. Same when filtering, when we filter for Guardian, we +/// probably don't want any Dragonhunters. +/// +/// So this enum unifies the handling between core specs and elite specs, and provides them with a +/// convenient [`Display`][Display] implementation as well. +#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] +pub enum PlayerClass { +    Profession(Profession), +    EliteSpec(EliteSpec), +} + +#[derive(Debug, Clone, Hash, PartialEq, Eq, Error)] +#[error("could not parse the class: {0}")] +pub struct ParsePlayerClassError(String); + +impl From<Profession> for PlayerClass { +    fn from(p: Profession) -> Self { +        PlayerClass::Profession(p) +    } +} + +impl From<EliteSpec> for PlayerClass { +    fn from(e: EliteSpec) -> Self { +        PlayerClass::EliteSpec(e) +    } +} + +impl FromStr for PlayerClass { +    type Err = ParsePlayerClassError; + +    fn from_str(s: &str) -> Result<Self, Self::Err> { +        let err = ParsePlayerClassError(s.to_owned()); +        Profession::from_str(s) +            .map(Into::into) +            .map_err(|_| err.clone()) +            .or_else(|_| EliteSpec::from_str(s).map(Into::into).map_err(|_| err)) +    } +} + +impl From<(Profession, Option<EliteSpec>)> for PlayerClass { +    fn from((profession, elite_spec): (Profession, Option<EliteSpec>)) -> Self { +        if let Some(spec) = elite_spec { +            spec.into() +        } else { +            profession.into() +        } +    } +} + +impl fmt::Display for PlayerClass { +    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +        use EliteSpec::*; +        use Profession::*; + +        let name = match *self { +            PlayerClass::EliteSpec(elite) => match elite { +                Dragonhunter => "Dragonhunter", +                Firebrand => "Firebrand", +                Berserker => "Berserker", +                Spellbreaker => "Spellbreaker", +                Herald => "Herald", +                Renegade => "Renegade", +                Scrapper => "Scrapper", +                Holosmith => "Holosmith", +                Druid => "Druid", +                Soulbeast => "Soulbeast", +                Daredevil => "Daredevil", +                Deadeye => "Deadeye", +                Tempest => "Tempest", +                Weaver => "Weaver", +                Chronomancer => "Chronomancer", +                Mirage => "Mirage", +                Reaper => "Reaper", +                Scourge => "Scourge", +            }, +            PlayerClass::Profession(prof) => match prof { +                Guardian => "Guardian", +                Warrior => "Warrior", +                Revenant => "Revenant", +                Engineer => "Engineer", +                Ranger => "Ranger", +                Thief => "Thief", +                Elementalist => "Elementalist", +                Mesmer => "Mesmer", +                Necromancer => "Necromancer", +            }, +        }; +        write!(f, "{}", name) +    } +} + +#[cfg(test)] +mod tests { +    use super::*; + +    #[test] +    fn test_player_class_from() { +        let tests: &[(Profession, Option<EliteSpec>, PlayerClass)] = &[ +            ( +                Profession::Guardian, +                None, +                PlayerClass::Profession(Profession::Guardian), +            ), +            ( +                Profession::Guardian, +                Some(EliteSpec::Dragonhunter), +                PlayerClass::EliteSpec(EliteSpec::Dragonhunter), +            ), +        ]; + +        for (prof, elite_spec, expected) in tests { +            assert_eq!(PlayerClass::from((*prof, *elite_spec)), *expected); +        } +    } + +    #[test] +    fn test_parse_player_class() { +        let tests: &[(&'static str, PlayerClass)] = &[ +            ("guardian", Profession::Guardian.into()), +            ("dragonhunter", EliteSpec::Dragonhunter.into()), +            ("warrior", Profession::Warrior.into()), +            ("scourge", EliteSpec::Scourge.into()), +        ]; + +        for (input, expected) in tests { +            assert_eq!(input.parse(), Ok(*expected)); +        } +    } +} | 
