aboutsummaryrefslogtreecommitdiff
path: root/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib.rs')
-rw-r--r--src/lib.rs123
1 files changed, 67 insertions, 56 deletions
diff --git a/src/lib.rs b/src/lib.rs
index 72b35ef..05f9f2d 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -40,7 +40,7 @@ pub enum EvtcError {
#[error("invalid elite specialization id: {0}")]
InvalidEliteSpec(u32),
#[error("utf8 decoding error: {0}")]
- Utf8Error(#[from] std::string::FromUtf8Error),
+ Utf8Error(#[from] std::str::Utf8Error),
}
/// Player-specific agent data.
@@ -113,6 +113,71 @@ pub enum AgentKind {
}
impl AgentKind {
+ fn from_raw_character(raw_agent: &raw::Agent) -> Result<Character, EvtcError> {
+ assert!(raw_agent.is_character());
+ let name = raw::cstr_up_to_nul(&raw_agent.name).ok_or(EvtcError::InvalidData)?;
+ Ok(Character {
+ id: raw_agent.prof as u16,
+ name: name.to_str()?.to_owned(),
+ })
+ }
+
+ fn from_raw_gadget(raw_agent: &raw::Agent) -> Result<Gadget, EvtcError> {
+ assert!(raw_agent.is_gadget());
+ let name = raw::cstr_up_to_nul(&raw_agent.name).ok_or(EvtcError::InvalidData)?;
+ Ok(Gadget {
+ id: raw_agent.prof as u16,
+ name: name.to_str()?.to_owned(),
+ })
+ }
+
+ fn from_raw_player(raw_agent: &raw::Agent) -> Result<Player, EvtcError> {
+ assert!(raw_agent.is_player());
+ let character_name = raw::cstr_up_to_nul(&raw_agent.name)
+ .ok_or(EvtcError::InvalidData)?
+ .to_str()?;
+ let account_name = raw::cstr_up_to_nul(&raw_agent.name[character_name.len() + 1..])
+ .ok_or(EvtcError::InvalidData)?
+ .to_str()?;
+ let subgroup = raw_agent.name[character_name.len() + account_name.len() + 2] - b'0';
+ let elite = if raw_agent.is_elite == 0 {
+ None
+ } else {
+ Some(
+ EliteSpec::from_u32(raw_agent.is_elite)
+ .ok_or(EvtcError::InvalidEliteSpec(raw_agent.is_elite))?,
+ )
+ };
+ Ok(Player {
+ profession: Profession::from_u32(raw_agent.prof)
+ .ok_or(EvtcError::InvalidProfession(raw_agent.prof))?,
+ elite,
+ character_name: character_name.to_owned(),
+ account_name: account_name.to_owned(),
+ subgroup,
+ })
+ }
+
+ /// Extract the correct `AgentKind` from the given [raw agent][raw::Agent].
+ ///
+ /// This automatically discerns between player, gadget and characters.
+ ///
+ /// Note that in most cases, you probably want to use [`Agent::from_raw`][Agent::from_raw] or
+ /// even [`process`][process] instead of this function.
+ pub fn from_raw(raw_agent: &raw::Agent) -> Result<AgentKind, EvtcError> {
+ if raw_agent.is_character() {
+ Ok(AgentKind::Character(AgentKind::from_raw_character(
+ raw_agent,
+ )?))
+ } else if raw_agent.is_gadget() {
+ Ok(AgentKind::Gadget(AgentKind::from_raw_gadget(raw_agent)?))
+ } else if raw_agent.is_player() {
+ Ok(AgentKind::Player(AgentKind::from_raw_player(raw_agent)?))
+ } else {
+ Err(EvtcError::InvalidData)
+ }
+ }
+
/// Accesses the inner [`Player`][Player] struct, if available.
pub fn as_player(&self) -> Option<&Player> {
if let AgentKind::Player(ref player) = *self {
@@ -268,61 +333,7 @@ pub struct Agent<Kind = ()> {
impl Agent {
/// Parse a raw agent.
pub fn from_raw(raw_agent: &raw::Agent) -> Result<Agent, EvtcError> {
- let kind = if raw_agent.is_character() || raw_agent.is_gadget() {
- let name = String::from_utf8(
- raw_agent
- .name
- .iter()
- .cloned()
- .take_while(|c| *c != 0)
- .collect::<Vec<_>>(),
- )?;
- if raw_agent.is_character() {
- AgentKind::Character(Character {
- id: raw_agent.prof as u16,
- name,
- })
- } else {
- AgentKind::Gadget(Gadget {
- id: raw_agent.prof as u16,
- name,
- })
- }
- } else if raw_agent.is_player() {
- let first = raw_agent
- .name
- .iter()
- .cloned()
- .take_while(|c| *c != 0)
- .collect::<Vec<_>>();
- let second = raw_agent
- .name
- .iter()
- .cloned()
- .skip(first.len() + 1)
- .take_while(|c| *c != 0)
- .collect::<Vec<_>>();
- let third = raw_agent.name[first.len() + second.len() + 2] - b'0';
- let elite = if raw_agent.is_elite == 0 {
- None
- } else {
- Some(
- EliteSpec::from_u32(raw_agent.is_elite)
- .ok_or(EvtcError::InvalidEliteSpec(raw_agent.is_elite))?,
- )
- };
- AgentKind::Player(Player {
- profession: Profession::from_u32(raw_agent.prof)
- .ok_or(EvtcError::InvalidProfession(raw_agent.prof))?,
- elite,
- character_name: String::from_utf8(first)?,
- account_name: String::from_utf8(second)?,
- subgroup: third,
- })
- } else {
- return Err(EvtcError::InvalidData);
- };
-
+ let kind = AgentKind::from_raw(raw_agent)?;
Ok(Agent {
addr: raw_agent.addr,
kind,