#![warn(clippy::all)]
#![deny(missing_docs)]
#![forbid(unused_must_use)]
#![feature(type_alias_enum_variants)]
use serde::{Deserialize, Serialize};
mod ability;
mod attribute;
mod cost;
mod ids;
mod race;
mod requirement;
mod unittype;
mod upgrade;
mod weapon;
pub use serde_json::Error as DeserializeError;
pub use self::ability::Ability;
pub use self::attribute::Attribute;
pub use self::cost::Cost;
pub use self::ids::*;
pub use self::race::Race;
pub use self::requirement::Requirement;
pub use self::unittype::UnitType;
pub use self::upgrade::Upgrade;
pub use self::weapon::*;
use self::ability::{AbilityResearch, AbilityTarget};
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum QueryError {
NotFound,
}
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
pub struct TechData {
#[serde(rename = "Ability")]
pub abilities: Vec<Ability>,
#[serde(rename = "Unit")]
pub unittypes: Vec<UnitType>,
#[serde(rename = "Upgrade")]
pub upgrades: Vec<Upgrade>,
}
impl TechData {
pub fn current() -> Self {
serde_json::from_str::<TechData>(include_str!("../data/data.json")).expect("Invalid bundled data")
}
pub fn from_json(source: &str) -> Result<Self, DeserializeError> {
serde_json::from_str::<TechData>(source)
}
pub fn ability(&self, ability_id: AbilityId) -> Option<Ability> {
for ability in &self.abilities {
if ability.id == ability_id {
return Some(ability.clone());
}
}
None
}
pub fn upgrade(&self, upgrade_id: UpgradeId) -> Option<Upgrade> {
for upgrade in &self.upgrades {
if upgrade.id == upgrade_id {
return Some(upgrade.clone());
}
}
None
}
pub fn unittype(&self, unittype_id: UnitTypeId) -> Option<UnitType> {
for unittype in &self.unittypes {
if unittype.id == unittype_id {
return Some(unittype.clone());
}
}
None
}
pub fn upgrade_ability(&self, upgrade_id: UpgradeId) -> Result<Ability, QueryError> {
for ability in &self.abilities {
if let AbilityTarget::Research(AbilityResearch { upgrade }) = ability.target {
if upgrade == upgrade_id {
return Ok(ability.clone());
}
}
}
Err(QueryError::NotFound)
}
}
#[cfg(test)]
mod tests {
use super::{QueryError, TechData, UpgradeId};
use std::fs::File;
use std::io::prelude::*;
#[test]
fn load_data() {
let mut f = File::open("data/data.json").expect("File not found");
let mut contents = String::new();
f.read_to_string(&mut contents).expect("Could not read");
TechData::from_json(&contents).expect("Deserialization failed");
}
#[test]
fn upgrade_ability() {
let td = TechData::current();
assert_eq!(
td.upgrade_ability(UpgradeId::new(64)).unwrap().name,
"RESEARCH_BURROW"
);
assert_eq!(
td.upgrade_ability(UpgradeId::new(86)).unwrap().name,
"RESEARCH_CHARGE"
);
assert_eq!(
td.upgrade_ability(UpgradeId::new(123_456)),
Err(QueryError::NotFound)
);
}
}