aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main.rs51
-rw-r--r--src/playerclass.rs141
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));
+ }
+ }
+}