ed_journals/modules/galaxy/models/
planet_class.rs1use crate::from_str_deserialize_impl;
2use serde::Serialize;
3use std::fmt::{Display, Formatter};
4use std::str::FromStr;
5use thiserror::Error;
6
7#[derive(Debug, Serialize, Clone, PartialEq, Eq, Hash)]
8pub enum PlanetClass {
9 MetalRichBody,
10 HighMetalContentBody,
11 RockyBody,
12 IcyBody,
13 RockyIceBody,
14 EarthlikeBody,
15 WaterWorld,
16 AmmoniaWorld,
17 WaterGiant,
18 WaterGiantWithLife,
19 GasGiantWithWaterBasedLife,
20 GasGiantWithAmmoniaBasedLife,
21 SudarskyClassIGasGiant,
22 SudarskyClassIIGasGiant,
23 SudarskyClassIIIGasGiant,
24 SudarskyClassIVGasGiant,
25 SudarskyClassVGasGiant,
26 HeliumRichGasGiant,
27 HeliumGasGiant,
28
29 #[cfg(feature = "allow-unknown")]
30 #[cfg_attr(docsrs, doc(cfg(feature = "allow-unknown")))]
31 Unknown(String),
32}
33
34#[derive(Debug, Error)]
35pub enum PlanetClassError {
36 #[error("Failed to parse planet class: '{0}'")]
37 FailedToParse(String),
38
39 #[error("Unknown planet class: '{0}'")]
40 UnknownPlanetClass(String),
41}
42
43impl FromStr for PlanetClass {
44 type Err = PlanetClassError;
45
46 fn from_str(s: &str) -> Result<Self, Self::Err> {
47 let string = s.to_ascii_lowercase().replace('_', " ");
48
49 let s: &str = string
50 .trim_end_matches('s')
51 .trim_end_matches(" body")
52 .trim_end_matches(" world");
53
54 Ok(match s {
55 "metal rich" => PlanetClass::MetalRichBody,
56 "high metal content" => PlanetClass::HighMetalContentBody,
57 "rocky" => PlanetClass::RockyBody,
58 "icy" | "ice" => PlanetClass::IcyBody,
59 "rocky ice" => PlanetClass::RockyIceBody,
60 "earthlike" | "earth like" | "earth-like" => PlanetClass::EarthlikeBody,
61 "water" => PlanetClass::WaterWorld,
62 "ammonia" => PlanetClass::AmmoniaWorld,
63 "water giant" => PlanetClass::WaterGiant,
64 "water giant with life" => PlanetClass::WaterGiantWithLife,
65 "gas giant with water based life" | "giant with water life" => {
66 PlanetClass::GasGiantWithWaterBasedLife
67 }
68 "gas giant with ammonia based life" | "giant with ammonia life" => {
69 PlanetClass::GasGiantWithAmmoniaBasedLife
70 }
71 "sudarsky class i gas giant" | "sudarsky class i" => {
72 PlanetClass::SudarskyClassIGasGiant
73 }
74 "sudarsky class ii gas giant" | "sudarsky class ii" => {
75 PlanetClass::SudarskyClassIIGasGiant
76 }
77 "sudarsky class iii gas giant" | "sudarsky class iii" => {
78 PlanetClass::SudarskyClassIIIGasGiant
79 }
80 "sudarsky class iv gas giant" | "sudarsky class iv" => {
81 PlanetClass::SudarskyClassIVGasGiant
82 }
83 "sudarsky class v gas giant" | "sudarsky class v" => {
84 PlanetClass::SudarskyClassVGasGiant
85 }
86 "helium rich gas giant" => PlanetClass::HeliumRichGasGiant,
87 "helium gas giant" => PlanetClass::HeliumGasGiant,
88
89 #[cfg(feature = "allow-unknown")]
90 _ => PlanetClass::Unknown(s.to_string()),
91
92 #[cfg(not(feature = "allow-unknown"))]
93 _ => return Err(PlanetClassError::UnknownPlanetClass(s.to_string())),
94 })
95 }
96}
97
98from_str_deserialize_impl!(PlanetClass);
99
100impl PlanetClass {
101 pub fn base_value(&self) -> u64 {
103 match self {
104 PlanetClass::MetalRichBody => 21_790,
105 PlanetClass::AmmoniaWorld => 96_932,
106 PlanetClass::SudarskyClassIGasGiant => 1_656,
107 PlanetClass::SudarskyClassIIGasGiant => 9_654,
108 PlanetClass::HighMetalContentBody => 9_654,
109 PlanetClass::WaterWorld => 64_831,
110 PlanetClass::EarthlikeBody => 64_831,
111 _ => 300,
112 }
113 }
114
115 pub fn terraformable_bonus(&self) -> u64 {
117 match self {
118 PlanetClass::MetalRichBody => 65_631,
119 PlanetClass::AmmoniaWorld => 0,
120 PlanetClass::SudarskyClassIGasGiant => 0,
121 PlanetClass::SudarskyClassIIGasGiant => 100_677,
122 PlanetClass::HighMetalContentBody => 100_677,
123 PlanetClass::WaterWorld => 116_295,
124 PlanetClass::EarthlikeBody => 116_295,
125 _ => 93_328,
126 }
127 }
128}
129
130impl Display for PlanetClass {
131 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
132 write!(
133 f,
134 "{}",
135 match self {
136 PlanetClass::MetalRichBody => "Metal Rich Body",
137 PlanetClass::HighMetalContentBody => "High Metal Content Body",
138 PlanetClass::RockyBody => "Rocky Body",
139 PlanetClass::IcyBody => "Icy Body",
140 PlanetClass::RockyIceBody => "Rocky Ice Body",
141 PlanetClass::EarthlikeBody => "Earth-like Body",
142 PlanetClass::WaterWorld => "Water World",
143 PlanetClass::AmmoniaWorld => "Ammonia World",
144 PlanetClass::WaterGiant => "Water Giant",
145 PlanetClass::WaterGiantWithLife => "Water Giant with life",
146 PlanetClass::GasGiantWithWaterBasedLife => "Gas Giant with water based life",
147 PlanetClass::GasGiantWithAmmoniaBasedLife => "Gas Giant with ammonia based life",
148 PlanetClass::SudarskyClassIGasGiant => "Sudarsky Class I Gas Giant",
149 PlanetClass::SudarskyClassIIGasGiant => "Sudarsky Class II Gas Giant",
150 PlanetClass::SudarskyClassIIIGasGiant => "Sudarsky Class III Gas Giant",
151 PlanetClass::SudarskyClassIVGasGiant => "Sudarsky Class IV Gas Giant",
152 PlanetClass::SudarskyClassVGasGiant => "Sudarsky Class V Gas Giant",
153 PlanetClass::HeliumRichGasGiant => "Helium Rich Gas Giant",
154 PlanetClass::HeliumGasGiant => "Helium Gas Giant",
155
156 #[cfg(feature = "allow-unknown")]
157 PlanetClass::Unknown(unknown) =>
158 return write!(f, "Unknown planet class: '{unknown}'"),
159 }
160 )
161 }
162}
163
164#[cfg(test)]
165mod tests {
166 use super::*;
167
168 #[test]
170 fn conversion_soundness() {
171 let planets = [
172 PlanetClass::MetalRichBody,
173 PlanetClass::HighMetalContentBody,
174 PlanetClass::RockyBody,
175 PlanetClass::IcyBody,
176 PlanetClass::RockyIceBody,
177 PlanetClass::EarthlikeBody,
178 PlanetClass::WaterWorld,
179 PlanetClass::AmmoniaWorld,
180 PlanetClass::WaterGiant,
181 PlanetClass::WaterGiantWithLife,
182 PlanetClass::GasGiantWithWaterBasedLife,
183 PlanetClass::GasGiantWithAmmoniaBasedLife,
184 PlanetClass::SudarskyClassIGasGiant,
185 PlanetClass::SudarskyClassIIGasGiant,
186 PlanetClass::SudarskyClassIIIGasGiant,
187 PlanetClass::SudarskyClassIVGasGiant,
188 PlanetClass::SudarskyClassVGasGiant,
189 PlanetClass::HeliumRichGasGiant,
190 PlanetClass::HeliumGasGiant,
191 ];
192
193 for planet in planets {
194 let planet_string = planet.to_string();
195 let planet_json_string = format!("\"{planet_string}\"");
196 let planet_deserialized = serde_json::de::from_str::<PlanetClass>(&planet_json_string);
197 assert!(
198 planet_deserialized.is_ok(),
199 "Failed to deserialize {planet_string}: {planet_deserialized:?}"
200 );
201 assert_eq!(planet, planet_deserialized.unwrap());
202 }
203 }
204}