ed_journals/modules/galaxy/models/
planet_class.rsuse crate::from_str_deserialize_impl;
use serde::Serialize;
use std::fmt::{Display, Formatter};
use std::str::FromStr;
use thiserror::Error;
#[derive(Debug, Serialize, Clone, PartialEq, Eq, Hash)]
pub enum PlanetClass {
MetalRichBody,
HighMetalContentBody,
RockyBody,
IcyBody,
RockyIceBody,
EarthlikeBody,
WaterWorld,
AmmoniaWorld,
WaterGiant,
WaterGiantWithLife,
GasGiantWithWaterBasedLife,
GasGiantWithAmmoniaBasedLife,
SudarskyClassIGasGiant,
SudarskyClassIIGasGiant,
SudarskyClassIIIGasGiant,
SudarskyClassIVGasGiant,
SudarskyClassVGasGiant,
HeliumRichGasGiant,
HeliumGasGiant,
#[cfg(feature = "allow-unknown")]
#[cfg_attr(docsrs, doc(cfg(feature = "allow-unknown")))]
Unknown(String),
}
#[derive(Debug, Error)]
pub enum PlanetClassError {
#[error("Failed to parse planet class: '{0}'")]
FailedToParse(String),
#[error("Unknown planet class: '{0}'")]
UnknownPlanetClass(String),
}
impl FromStr for PlanetClass {
type Err = PlanetClassError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let string = s.to_ascii_lowercase().replace('_', " ");
let s: &str = string
.trim_end_matches('s')
.trim_end_matches(" body")
.trim_end_matches(" world");
Ok(match s {
"metal rich" => PlanetClass::MetalRichBody,
"high metal content" => PlanetClass::HighMetalContentBody,
"rocky" => PlanetClass::RockyBody,
"icy" | "ice" => PlanetClass::IcyBody,
"rocky ice" => PlanetClass::RockyIceBody,
"earthlike" | "earth like" | "earth-like" => PlanetClass::EarthlikeBody,
"water" => PlanetClass::WaterWorld,
"ammonia" => PlanetClass::AmmoniaWorld,
"water giant" => PlanetClass::WaterGiant,
"water giant with life" => PlanetClass::WaterGiantWithLife,
"gas giant with water based life" | "giant with water life" => {
PlanetClass::GasGiantWithWaterBasedLife
}
"gas giant with ammonia based life" | "giant with ammonia life" => {
PlanetClass::GasGiantWithAmmoniaBasedLife
}
"sudarsky class i gas giant" | "sudarsky class i" => {
PlanetClass::SudarskyClassIGasGiant
}
"sudarsky class ii gas giant" | "sudarsky class ii" => {
PlanetClass::SudarskyClassIIGasGiant
}
"sudarsky class iii gas giant" | "sudarsky class iii" => {
PlanetClass::SudarskyClassIIIGasGiant
}
"sudarsky class iv gas giant" | "sudarsky class iv" => {
PlanetClass::SudarskyClassIVGasGiant
}
"sudarsky class v gas giant" | "sudarsky class v" => {
PlanetClass::SudarskyClassVGasGiant
}
"helium rich gas giant" => PlanetClass::HeliumRichGasGiant,
"helium gas giant" => PlanetClass::HeliumGasGiant,
#[cfg(feature = "allow-unknown")]
_ => PlanetClass::Unknown(s.to_string()),
#[cfg(not(feature = "allow-unknown"))]
_ => return Err(PlanetClassError::UnknownPlanetClass(s.to_string())),
})
}
}
from_str_deserialize_impl!(PlanetClass);
impl PlanetClass {
pub fn base_value(&self) -> u64 {
match self {
PlanetClass::MetalRichBody => 21_790,
PlanetClass::AmmoniaWorld => 96_932,
PlanetClass::SudarskyClassIGasGiant => 1_656,
PlanetClass::SudarskyClassIIGasGiant => 9_654,
PlanetClass::HighMetalContentBody => 9_654,
PlanetClass::WaterWorld => 64_831,
PlanetClass::EarthlikeBody => 64_831,
_ => 300,
}
}
pub fn terraformable_bonus(&self) -> u64 {
match self {
PlanetClass::MetalRichBody => 65_631,
PlanetClass::AmmoniaWorld => 0,
PlanetClass::SudarskyClassIGasGiant => 0,
PlanetClass::SudarskyClassIIGasGiant => 100_677,
PlanetClass::HighMetalContentBody => 100_677,
PlanetClass::WaterWorld => 116_295,
PlanetClass::EarthlikeBody => 116_295,
_ => 93_328,
}
}
}
impl Display for PlanetClass {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
PlanetClass::MetalRichBody => "Metal Rich Body",
PlanetClass::HighMetalContentBody => "High Metal Content Body",
PlanetClass::RockyBody => "Rocky Body",
PlanetClass::IcyBody => "Icy Body",
PlanetClass::RockyIceBody => "Rocky Ice Body",
PlanetClass::EarthlikeBody => "Earth-like Body",
PlanetClass::WaterWorld => "Water World",
PlanetClass::AmmoniaWorld => "Ammonia World",
PlanetClass::WaterGiant => "Water Giant",
PlanetClass::WaterGiantWithLife => "Water Giant with life",
PlanetClass::GasGiantWithWaterBasedLife => "Gas Giant with water based life",
PlanetClass::GasGiantWithAmmoniaBasedLife => "Gas Giant with ammonia based life",
PlanetClass::SudarskyClassIGasGiant => "Sudarsky Class I Gas Giant",
PlanetClass::SudarskyClassIIGasGiant => "Sudarsky Class II Gas Giant",
PlanetClass::SudarskyClassIIIGasGiant => "Sudarsky Class III Gas Giant",
PlanetClass::SudarskyClassIVGasGiant => "Sudarsky Class IV Gas Giant",
PlanetClass::SudarskyClassVGasGiant => "Sudarsky Class V Gas Giant",
PlanetClass::HeliumRichGasGiant => "Helium Rich Gas Giant",
PlanetClass::HeliumGasGiant => "Helium Gas Giant",
#[cfg(feature = "allow-unknown")]
PlanetClass::Unknown(unknown) =>
return write!(f, "Unknown planet class: '{}'", unknown),
}
)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn conversion_soundness() {
let planets = [
PlanetClass::MetalRichBody,
PlanetClass::HighMetalContentBody,
PlanetClass::RockyBody,
PlanetClass::IcyBody,
PlanetClass::RockyIceBody,
PlanetClass::EarthlikeBody,
PlanetClass::WaterWorld,
PlanetClass::AmmoniaWorld,
PlanetClass::WaterGiant,
PlanetClass::WaterGiantWithLife,
PlanetClass::GasGiantWithWaterBasedLife,
PlanetClass::GasGiantWithAmmoniaBasedLife,
PlanetClass::SudarskyClassIGasGiant,
PlanetClass::SudarskyClassIIGasGiant,
PlanetClass::SudarskyClassIIIGasGiant,
PlanetClass::SudarskyClassIVGasGiant,
PlanetClass::SudarskyClassVGasGiant,
PlanetClass::HeliumRichGasGiant,
PlanetClass::HeliumGasGiant,
];
for planet in planets {
let planet_string = planet.to_string();
let planet_json_string = format!("\"{}\"", planet_string);
let planet_deserialized = serde_json::de::from_str::<PlanetClass>(&planet_json_string);
assert!(
planet_deserialized.is_ok(),
"Failed to deserialize {}: {:?}",
planet_string,
planet_deserialized
);
assert_eq!(planet, planet_deserialized.unwrap());
}
}
}