lib_efo/stats/implementations/
from_impl.rs1use crate::stats::FactionId;
4use crate::{
5 error::EpochError,
6 stats::{self, GenericStat, ListStats, Position, PositionGrid, PositionIdentifier, StatPair},
7};
8use std::str::FromStr;
9
10impl FromStr for StatPair {
11 type Err = EpochError;
12
13 fn from_str(s: &str) -> Result<Self, Self::Err> {
19 let (stat_str, val_str) = if let Some(idx) = s.find([':', '=']) {
20 (&s[..idx], &s[idx + 1..])
21 } else {
22 let parts: Vec<&str> = s.split_whitespace().collect();
23 if parts.len() != 2 {
24 return Err(EpochError::IllFormedStatQualifier(s.to_owned()));
25 }
26 (parts[0], parts[1])
27 };
28
29 let stat: ListStats = stat_str.parse()?;
30 let value: isize = val_str
31 .parse()
32 .map_err(|_| EpochError::IllFormedStatQualifier(val_str.to_owned()))?;
33 Ok(StatPair {
34 stat,
35 value: stats::GenericStat(value),
36 })
37 }
38}
39
40impl std::str::FromStr for Position {
53 type Err = EpochError;
54
55 fn from_str(s: &str) -> Result<Self, Self::Err> {
56 let parts: Vec<&str> = s.split(',').collect();
57 if parts.len() != 2 {
58 return Err(EpochError::InvalidPositionFormat(s.to_string()));
59 }
60 let x: isize = parts[0]
61 .trim()
62 .parse()
63 .map_err(|_| EpochError::ParsePositionError(s.to_string()))?;
64 let y: isize = parts[1]
65 .trim()
66 .parse()
67 .map_err(|_| EpochError::ParsePositionError(s.to_string()))?;
68 Ok(Position(x, y))
69 }
70}
71
72impl std::str::FromStr for PositionGrid {
92 type Err = EpochError;
93
94 fn from_str(s: &str) -> Result<Self, Self::Err> {
95 s.parse::<Position>().map(|p| PositionGrid(p.0, p.1))
96 }
97}
98
99impl FromStr for PositionIdentifier {
100 type Err = EpochError;
101
102 fn from_str(s: &str) -> Result<Self, Self::Err> {
106 let s = s.trim();
107
108 if let Some(_rest) = s.find('@') {
109 let id = s.parse().map_err(|_| EpochError::ParsingArgument {
110 argument_parsed: s.to_string(),
111 while_parsing: "PositionIdentifier::EpochId",
112 })?;
113 return Ok(Self::Id(id));
114 }
115
116 if let Some(rest) = s.strip_prefix('~').or_else(|| s.strip_prefix('g')) {
117 let grid = rest.parse().map_err(|_| EpochError::ParsingArgument {
118 argument_parsed: s.to_string(),
119 while_parsing: "PositionIdentifier::PositionGrid",
120 })?;
121 return Ok(Self::Grid(grid));
122 }
123
124 let exact = s.parse().map_err(|_| EpochError::ParsingArgument {
125 argument_parsed: s.to_string(),
126 while_parsing: "PositionIdentifier::Position",
127 })?;
128 Ok(Self::Exact(exact))
129 }
130}
131
132impl From<(isize, isize)> for Position {
138 fn from(value: (isize, isize)) -> Self {
139 Self(value.0, value.1)
140 }
141}
142impl From<(isize, isize)> for PositionGrid {
148 fn from(value: (isize, isize)) -> Self {
149 Self(value.0, value.1)
150 }
151}
152impl std::str::FromStr for stats::Reach {
153 type Err = EpochError; fn from_str(s: &str) -> Result<Self, Self::Err> {
156 let s = s.trim().to_ascii_lowercase();
157
158 match s.as_str() {
159 "g" | "global" => return Ok(stats::Reach::Global),
160 "n" | "none" => return Ok(stats::Reach::None),
161 _ => {}
162 }
163
164 if s.starts_with('l') {
165 if let Some(idx) = s.find(':') {
166 let rad_str = &s[idx + 1..];
167 let radius: usize = rad_str.parse().map_err(|_| EpochError::ParsingArgument {
168 argument_parsed: s,
169 while_parsing: "Reach::Local",
170 })?;
171 return Ok(stats::Reach::Local(radius));
172 } else {
173 return Err(EpochError::ParsingArgument {
174 argument_parsed: s,
175 while_parsing: "Local reach requires a radius, e.g. `l:5` or `local:5`",
176 });
177 }
178 }
179
180 if s.starts_with('f') {
181 if let Some(idx) = s.find(':') {
182 let id_str = &s[idx + 1..];
183 let id: usize = id_str.parse().map_err(|_| EpochError::ParsingArgument {
184 argument_parsed: s,
185 while_parsing: "Reach::Faction",
186 })?;
187 return Ok(stats::Reach::Faction(stats::FactionId(id)));
188 } else {
189 return Err(EpochError::ParsingArgument {
190 argument_parsed: s,
191 while_parsing: "Faction reach requires an id, e.g. `f:3` or `faction:3`",
192 });
193 }
194 }
195
196 Err(EpochError::ParsingArgument {
197 argument_parsed: s,
198 while_parsing: "Unknown error",
199 })
200 }
201}
202
203impl FromStr for GenericStat {
204 type Err = EpochError;
205
206 fn from_str(s: &str) -> Result<Self, Self::Err> {
207 s.parse::<isize>()
208 .map_err(|_| EpochError::ParsingArgument {
209 argument_parsed: s.to_owned(),
210 while_parsing: "GenericStat",
211 })
212 .map(Self)
213 }
214}
215
216impl std::str::FromStr for stats::Modification {
217 type Err = EpochError; fn from_str(s: &str) -> Result<Self, Self::Err> {
220 match s.to_ascii_lowercase().as_str() {
221 w if w.starts_with("delt") => Ok(stats::Modification::Delta),
222 "add" => Ok(stats::Modification::Delta),
223 w if w.starts_with("repl") => Ok(stats::Modification::Replace),
224 "change" => Ok(stats::Modification::Replace),
225 w if w.starts_with("del") => Ok(stats::Modification::Delete),
226 _ => Err(EpochError::ParsingArgument {
227 argument_parsed: s.to_owned(),
228 while_parsing: "Modification",
229 }), }
231 }
232}
233
234impl From<bool> for stats::Modification {
235 fn from(value: bool) -> Self {
236 match value {
237 true => stats::Modification::Delta,
238 false => stats::Modification::Replace,
239 }
240 }
241}
242
243impl FromStr for FactionId {
244 type Err = EpochError; fn from_str(s: &str) -> Result<Self, Self::Err> {
248 let inner = s
250 .trim()
251 .parse::<usize>()
252 .map_err(|_| EpochError::ParsingArgument {
253 argument_parsed: s.to_string(),
254 while_parsing: "FactionId",
255 })?;
256 Ok(FactionId(inner))
257 }
258}
259
260impl FromStr for ListStats {
261 type Err = EpochError;
262
263 fn from_str(s: &str) -> Result<Self, Self::Err> {
265 match s.to_ascii_lowercase().as_str() {
266 "dem" | "demog" | "demographics" | "demo" => Ok(ListStats::Demographics),
267 "pop" | "popul" | "populations" => Ok(ListStats::Population),
268 "grow" | "grw" | "growth" => Ok(ListStats::Growthrate),
269 "cri" | "crim" | "crimes" => Ok(ListStats::Crime),
270 "hapn" | "happines" | "hap" => Ok(ListStats::Happiness),
271 "eco" | "economy" | "econ" => Ok(ListStats::Economy),
272 "food" | "fo" | "agr" | "agri" | "fod" => Ok(ListStats::Food),
273 "industry" | "indus" | "ind" => Ok(ListStats::Industry),
274 "science" | "sci" | "sc" => Ok(ListStats::Science),
275 "trade" | "trd" | "tr" => Ok(ListStats::Trade),
276 "social" | "soc" | "sl" => Ok(ListStats::Social),
277 "culture" | "cul" | "cl" => Ok(ListStats::Culture),
278 "education" | "edu" | "ed" => Ok(ListStats::Education),
279 "tourism" | "tour" | "tm" => Ok(ListStats::Tourism),
280 "influence" | "infl" | "influ" => Ok(ListStats::Influence),
281 "military" | "mil" | "mt" => Ok(ListStats::Military),
282 "army" | "arm" | "ar" => Ok(ListStats::Army),
283 "strength" | "str" | "st" => Ok(ListStats::Strength),
284 "fortification" | "fort" | "ft" => Ok(ListStats::Fortification),
285 "threat" | "thr" | "th" => Ok(ListStats::Threat),
286 "ifr" | "inf" | "infrastructure" | "infra" | "infr" => Ok(ListStats::Infrastructure),
287 "bureaucracy" | "bureau" | "bur" => Ok(ListStats::Bureaucracy),
288 "transportation" | "trans" | "trns" => Ok(ListStats::Transportation),
289 "sprawl" | "spr" | "spra" => Ok(ListStats::Sprawl),
290 "health" | "hlth" | "hlt" => Ok(ListStats::Health),
291 _ => Err(EpochError::UnknownStatAcronim(s.to_owned())),
292 }
293 }
294}
295
296impl From<ListStats> for &str {
297 fn from(value: ListStats) -> Self {
298 match value {
299 ListStats::Demographics => "demographics",
300 ListStats::Population => "population",
301 ListStats::Growthrate => "growthrate",
302 ListStats::Crime => "crime",
303 ListStats::Happiness => "happiness",
304 ListStats::Economy => "economy",
305 ListStats::Food => "food",
306 ListStats::Industry => "industry",
307 ListStats::Science => "science",
308 ListStats::Trade => "trade",
309 ListStats::Social => "social",
310 ListStats::Culture => "culture",
311 ListStats::Education => "education",
312 ListStats::Tourism => "tourism",
313 ListStats::Influence => "influence",
314 ListStats::Military => "military",
315 ListStats::Army => "army",
316 ListStats::Strength => "strength",
317 ListStats::Fortification => "fortification",
318 ListStats::Threat => "threat",
319 ListStats::Infrastructure => "infrastructure",
320 ListStats::Bureaucracy => "bureaucracy",
321 ListStats::Transportation => "transportation",
322 ListStats::Sprawl => "sprawl",
323 ListStats::Health => "health",
324 }
325 }
326}