ed_journals/modules/exploration/models/
codex_entry.rs1use crate::exploration::models::codex_anomaly_entry::CodexAnomalyEntry;
2use crate::exploration::models::codex_geological_entry::CodexGeologicalEntry;
3use crate::exploration::models::codex_guardian_entry::CodexGuardianEntry;
4use crate::exploration::models::codex_organic_structure_entry::CodexOrganicStructureEntry;
5use crate::exploration::models::codex_planet_entry::CodexPlanetEntry;
6use crate::exploration::models::codex_thargoid_entry::CodexThargoidEntry;
7use crate::from_str_deserialize_impl;
8use crate::modules::exobiology::{Genus, Species, Variant};
9use crate::modules::exploration::CodexStarClassEntry;
10use serde::Serialize;
11use std::fmt::{Display, Formatter};
12use std::str::FromStr;
13use thiserror::Error;
14
15#[derive(Debug, Serialize, Clone, PartialEq, Eq, Hash)]
17#[cfg_attr(not(feature = "allow-unknown"), non_exhaustive)]
18pub enum CodexEntry {
19 Planet(CodexPlanetEntry),
20 Geological(CodexGeologicalEntry),
21 Anomalous(CodexAnomalyEntry),
22 Thargoid(CodexThargoidEntry),
23 Guardian(CodexGuardianEntry),
24 Genus(Genus),
25 Species(Species),
26 Variant(Variant),
27 OrganicStructure(CodexOrganicStructureEntry),
28 StarClass(CodexStarClassEntry),
29
30 #[cfg(feature = "allow-unknown")]
32 #[cfg_attr(docsrs, doc(cfg(feature = "allow-unknown")))]
33 Unknown(String),
34}
35
36impl CodexEntry {
37 #[cfg(feature = "allow-unknown")]
39 #[cfg_attr(docsrs, doc(cfg(feature = "allow-unknown")))]
40 pub fn is_unknown(&self) -> bool {
41 matches!(self, CodexEntry::Unknown(_))
42 }
43}
44
45#[derive(Debug, Error)]
46pub enum CodexEntryError {
47 #[error("Unknown codex entry: '{0}'")]
48 UnknownEntry(String),
49}
50
51impl FromStr for CodexEntry {
52 type Err = CodexEntryError;
53
54 #[cfg(not(feature = "allow-unknown"))]
55 fn from_str(s: &str) -> Result<Self, Self::Err> {
56 if let Ok(entry) = CodexPlanetEntry::from_str(s) {
57 return Ok(CodexEntry::Planet(entry));
58 }
59
60 if let Ok(entry) = CodexGeologicalEntry::from_str(s) {
61 return Ok(CodexEntry::Geological(entry));
62 }
63
64 if let Ok(entry) = CodexAnomalyEntry::from_str(s) {
65 return Ok(CodexEntry::Anomalous(entry));
66 }
67
68 if let Ok(entry) = CodexThargoidEntry::from_str(s) {
69 return Ok(CodexEntry::Thargoid(entry));
70 }
71
72 if let Ok(entry) = CodexGuardianEntry::from_str(s) {
73 return Ok(CodexEntry::Guardian(entry));
74 }
75
76 if let Ok(entry) = Genus::from_str(s) {
77 return Ok(CodexEntry::Genus(entry));
78 }
79
80 if let Ok(entry) = Species::from_str(s) {
81 return Ok(CodexEntry::Species(entry));
82 }
83
84 if let Ok(entry) = Variant::from_str(s) {
85 return Ok(CodexEntry::Variant(entry));
86 }
87
88 if let Ok(entry) = CodexOrganicStructureEntry::from_str(s) {
89 return Ok(CodexEntry::OrganicStructure(entry));
90 }
91
92 if let Ok(entry) = CodexStarClassEntry::from_str(s) {
93 return Ok(CodexEntry::StarClass(entry));
94 }
95
96 Err(CodexEntryError::UnknownEntry(s.to_string()))
97 }
98
99 #[cfg(feature = "allow-unknown")]
100 fn from_str(s: &str) -> Result<Self, Self::Err> {
101 if let Ok(entry) = CodexPlanetEntry::from_str(s) {
102 if !entry.is_unknown() {
103 return Ok(CodexEntry::Planet(entry));
104 }
105 }
106
107 if let Ok(entry) = CodexGeologicalEntry::from_str(s) {
108 if !entry.is_unknown() {
109 return Ok(CodexEntry::Geological(entry));
110 }
111 }
112
113 if let Ok(entry) = CodexAnomalyEntry::from_str(s) {
114 if !entry.is_unknown() {
115 return Ok(CodexEntry::Anomalous(entry));
116 }
117 }
118
119 if let Ok(entry) = CodexThargoidEntry::from_str(s) {
120 if !entry.is_unknown() {
121 return Ok(CodexEntry::Thargoid(entry));
122 }
123 }
124
125 if let Ok(entry) = CodexGuardianEntry::from_str(s) {
126 if !entry.is_unknown() {
127 return Ok(CodexEntry::Guardian(entry));
128 }
129 }
130
131 if let Ok(entry) = Genus::from_str(s) {
132 if !entry.is_unknown() {
133 return Ok(CodexEntry::Genus(entry));
134 }
135 }
136
137 if let Ok(entry) = Species::from_str(s) {
138 if !entry.is_unknown() {
139 return Ok(CodexEntry::Species(entry));
140 }
141 }
142
143 if let Ok(entry) = Variant::from_str(s) {
144 if !entry.is_unknown() {
145 return Ok(CodexEntry::Variant(entry));
146 }
147 }
148
149 if let Ok(entry) = CodexOrganicStructureEntry::from_str(s) {
150 if !entry.is_unknown() {
151 return Ok(CodexEntry::OrganicStructure(entry));
152 }
153 }
154
155 if let Ok(entry) = CodexStarClassEntry::from_str(s) {
156 if !entry.is_unknown() {
157 return Ok(CodexEntry::StarClass(entry));
158 }
159 }
160
161 Ok(CodexEntry::Unknown(s.to_string()))
162 }
163}
164
165from_str_deserialize_impl!(CodexEntry);
166
167impl Display for CodexEntry {
168 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
169 match self {
170 CodexEntry::Geological(geological) => write!(f, "{geological}"),
173 CodexEntry::Anomalous(anomalous) => write!(f, "{anomalous}"),
174 CodexEntry::Thargoid(targoid) => write!(f, "{targoid}"),
175 CodexEntry::Planet(planet_class) => write!(f, "{planet_class}"),
176 CodexEntry::Genus(genus) => write!(f, "{genus}"),
177 CodexEntry::Species(species) => write!(f, "{species}"),
178 CodexEntry::Variant(variant) => write!(f, "{variant}"),
179 CodexEntry::OrganicStructure(organic_structure) => write!(f, "{organic_structure}"),
180 CodexEntry::StarClass(star_class) => write!(f, "{star_class}"),
181 CodexEntry::Guardian(guardian) => write!(f, "{guardian}"),
182
183 #[cfg(feature = "allow-unknown")]
184 CodexEntry::Unknown(unknown) => write!(f, "Unknown: '{unknown}'"),
185 }
186 }
187}
188
189#[cfg(test)]
190mod tests {
191 use crate::exploration::CodexEntry;
192 use serde_json::Value;
193
194 #[test]
195 fn codex_entries_are_parsed_correctly() {
196 let content = include_str!("zz_codex_entries");
197 let lines = content.lines();
198
199 for line in lines {
200 if line.starts_with('#') {
201 continue;
202 }
203
204 let result = serde_json::from_value::<CodexEntry>(Value::String(line.to_string()));
205
206 if result.is_err() {
207 dbg!(&line, &result);
208 }
209
210 assert!(result.is_ok());
211 }
212 }
213
214 #[cfg(not(feature = "allow-unknown"))]
215 #[test]
216 fn unknown_value_returns_error() {
217 let result = serde_json::from_value::<CodexEntry>(Value::String("yeah no".to_string()));
218 assert!(result.is_err());
219 }
220
221 #[cfg(feature = "allow-unknown")]
222 #[test]
223 fn unknown_value_returns_unknown_variant() {
224 let result = serde_json::from_value::<CodexEntry>(Value::String("yeah no".to_string()));
225 assert_eq!(result.unwrap(), CodexEntry::Unknown("yeah no".to_string()));
226 }
227}