1use std::{convert::TryFrom, fmt::Display, str::FromStr};
2
3use serde::{Deserialize, Serialize};
4
5#[derive(Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, Debug)]
6pub enum Rank {
7 #[serde(rename = "1")]
8 Challenger = 1,
9
10 #[serde(rename = "2")]
11 Master = 2,
12
13 #[serde(rename = "3")]
14 Diamond = 3,
15
16 #[serde(rename = "4")]
17 Platinum = 4,
18
19 #[serde(rename = "5")]
20 Gold = 5,
21
22 #[serde(rename = "6")]
23 Silver = 6,
24
25 #[serde(rename = "7")]
26 Bronze = 7,
27
28 #[serde(rename = "8")]
29 Overall = 8,
30
31 #[serde(rename = "10")]
32 PlatinumPlus = 10,
33
34 #[serde(rename = "11")]
35 DiamondPlus = 11,
36
37 #[serde(rename = "12")]
38 Iron = 12,
39
40 #[serde(rename = "13")]
41 Grandmaster = 13,
42
43 #[serde(rename = "14")]
44 MasterPlus = 14,
45
46 #[serde(rename = "15")]
47 Diamond2Plus = 15,
48
49 #[serde(rename = "16")]
50 Emerald = 16,
51
52 #[serde(rename = "17")]
53 EmeraldPlus = 17,
54}
55
56impl Display for Rank {
57 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
58 let rank_str = match self {
59 Rank::Challenger => "Challenger",
60 Rank::Master => "Master",
61 Rank::Diamond => "Diamond",
62 Rank::Platinum => "Platinum",
63 Rank::Gold => "Gold",
64 Rank::Silver => "Silver",
65 Rank::Bronze => "Bronze",
66 Rank::Overall => "Overall",
67 Rank::PlatinumPlus => "PlatinumPlus",
68 Rank::DiamondPlus => "DiamondPlus",
69 Rank::Iron => "Iron",
70 Rank::Grandmaster => "Grandmaster",
71 Rank::MasterPlus => "MasterPlus",
72 Rank::Diamond2Plus => "Diamond2Plus",
73 Rank::Emerald => "Emerald",
74 Rank::EmeraldPlus => "EmeraldPlus",
75 };
76 write!(f, "{rank_str}")
77 }
78}
79
80impl Rank {
81 #[must_use]
82 pub const fn preferred_order() -> [Rank; 16] {
83 [
86 Rank::PlatinumPlus,
87 Rank::Overall,
88 Rank::EmeraldPlus,
89 Rank::DiamondPlus,
90 Rank::Diamond2Plus,
91 Rank::MasterPlus,
92 Rank::Iron,
93 Rank::Bronze,
94 Rank::Silver,
95 Rank::Gold,
96 Rank::Platinum,
97 Rank::Emerald,
98 Rank::Diamond,
99 Rank::Master,
100 Rank::Grandmaster,
101 Rank::Challenger,
102 ]
103 }
104}
105
106#[derive(Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, Debug, Default)]
107pub enum Region {
108 #[serde(rename = "1")]
109 NA1 = 1,
110
111 #[serde(rename = "2")]
112 EUW1,
113
114 #[serde(rename = "3")]
115 KR,
116
117 #[serde(rename = "4")]
118 EUN1,
119
120 #[serde(rename = "5")]
121 BR1,
122
123 #[serde(rename = "6")]
124 LA1,
125
126 #[serde(rename = "7")]
127 LA2,
128
129 #[serde(rename = "8")]
130 OC1,
131
132 #[serde(rename = "9")]
133 RU,
134
135 #[serde(rename = "10")]
136 TR1,
137
138 #[serde(rename = "11")]
139 JP1,
140
141 #[serde(rename = "12")]
142 #[default]
143 World,
144
145 #[serde(rename = "13")]
146 PH2,
147
148 #[serde(rename = "14")]
149 SG2,
150
151 #[serde(rename = "15")]
152 TH2,
153
154 #[serde(rename = "16")]
155 TW2,
156
157 #[serde(rename = "17")]
158 VN2,
159
160 #[serde(rename = "18")]
161 ME1,
162}
163
164impl Region {
165 #[must_use]
166 pub fn to_api_string(self) -> String {
167 (match self {
168 Region::NA1 => 1,
169 Region::EUW1 => 2,
170 Region::KR => 3,
171 Region::EUN1 => 4,
172 Region::BR1 => 5,
173 Region::LA1 => 6,
174 Region::LA2 => 7,
175 Region::OC1 => 8,
176 Region::RU => 9,
177 Region::TR1 => 10,
178 Region::JP1 => 11,
179 Region::World => 12,
180 Region::PH2 => 13,
181 Region::SG2 => 14,
182 Region::TH2 => 15,
183 Region::TW2 => 16,
184 Region::VN2 => 17,
185 Region::ME1 => 18,
186 })
187 .to_string()
188 }
189
190 #[must_use]
191 pub const fn all() -> &'static [Region; 18] {
192 &[
193 Region::NA1,
194 Region::EUW1,
195 Region::KR,
196 Region::EUN1,
197 Region::BR1,
198 Region::LA1,
199 Region::LA2,
200 Region::OC1,
201 Region::RU,
202 Region::TR1,
203 Region::JP1,
204 Region::World,
205 Region::PH2,
206 Region::SG2,
207 Region::TH2,
208 Region::TW2,
209 Region::VN2,
210 Region::ME1,
211 ]
212 }
213}
214
215impl Display for Region {
216 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
217 let region_str = match self {
218 Region::NA1 => "NA1",
219 Region::EUW1 => "EUW1",
220 Region::KR => "KR",
221 Region::EUN1 => "EUN1",
222 Region::BR1 => "BR1",
223 Region::LA1 => "LA1",
224 Region::LA2 => "LA2",
225 Region::OC1 => "OC1",
226 Region::RU => "RU",
227 Region::TR1 => "TR1",
228 Region::JP1 => "JP1",
229 Region::World => "World",
230 Region::PH2 => "PH2",
231 Region::SG2 => "SG2",
232 Region::TH2 => "TH2",
233 Region::TW2 => "TW2",
234 Region::VN2 => "VN2",
235 Region::ME1 => "ME1",
236 };
237 write!(f, "{region_str}")
238 }
239}
240
241#[must_use]
242pub fn get_region(region: &str) -> Region {
243 for enum_region in Region::all() {
244 let region_str = enum_region.to_string().to_lowercase();
245 if region.to_lowercase() == region_str
246 || region_str.contains(®ion.to_lowercase()[..region.len() - 1])
247 {
248 return *enum_region;
249 }
250 }
251 Region::World
252}
253
254impl FromStr for Region {
255 type Err = String;
256
257 fn from_str(s: &str) -> Result<Self, Self::Err> {
258 Ok(get_region(s))
259 }
260}
261
262#[derive(Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, Debug, Default)]
263pub enum Role {
264 #[serde(rename = "1")]
265 Jungle = 1,
266
267 #[serde(rename = "2")]
268 Support,
269
270 #[serde(rename = "3")]
271 ADCarry,
272
273 #[serde(rename = "4")]
274 Top,
275
276 #[serde(rename = "5")]
277 Mid,
278
279 #[serde(rename = "6")]
281 None,
282
283 #[serde(rename = "7")]
284 #[default]
285 Automatic,
286
287 #[serde(rename = "8")]
289 Lane,
290}
291
292impl Role {
293 #[must_use]
294 pub const fn all() -> &'static [Role; 8] {
295 &[
296 Role::Jungle,
297 Role::Support,
298 Role::ADCarry,
299 Role::Top,
300 Role::Mid,
301 Role::None,
302 Role::Automatic,
303 Role::Lane,
304 ]
305 }
306}
307
308impl Display for Role {
309 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
310 let role_str = match self {
311 Role::Jungle => "Jungle",
312 Role::Support => "Support",
313 Role::ADCarry => "ADCarry",
314 Role::Top => "Top",
315 Role::Mid => "Mid",
316 Role::None => "None",
317 Role::Automatic => "Automatic",
318 Role::Lane => "Lane",
319 };
320 write!(f, "{role_str}")
321 }
322}
323
324impl TryFrom<i32> for Role {
325 type Error = ();
326 fn try_from(v: i32) -> Result<Self, Self::Error> {
327 match v {
328 1 => Ok(Self::Jungle),
329 2 => Ok(Self::Support),
330 3 => Ok(Self::ADCarry),
331 4 => Ok(Self::Top),
332 5 => Ok(Self::Mid),
333 6 => Ok(Self::None),
334 7 => Ok(Self::Automatic),
335 8 => Ok(Self::Lane),
336 _ => Err(()),
337 }
338 }
339}
340
341#[must_use]
342pub fn get_role(role: &str) -> Role {
343 for enum_role in Role::all() {
344 let role_str = enum_role.to_string().to_lowercase();
345 if role_str.contains(&role.to_lowercase()) {
346 return *enum_role;
347 }
348 }
349 Role::Automatic
350}
351
352impl FromStr for Role {
353 type Err = String;
354
355 fn from_str(s: &str) -> Result<Self, Self::Err> {
356 Ok(get_role(s))
357 }
358}
359
360#[derive(Clone, Copy, Debug, PartialEq, Eq)]
361#[allow(clippy::upper_case_acronyms)]
362#[derive(Default)]
363pub enum Mode {
364 #[default]
365 Normal,
366 ARAM,
367 OneForAll,
368 URF,
369 ARURF,
370 NexusBlitz,
371 Arena,
372}
373
374impl Mode {
375 #[must_use]
376 pub fn to_api_string(self) -> String {
377 (match self {
378 Self::Normal => "ranked_solo_5x5",
379 Self::ARAM => "normal_aram",
380 Self::OneForAll => "one_for_all",
381 Self::URF => "pick_urf",
382 Self::ARURF => "urf",
383 Self::NexusBlitz => "nexus_blitz",
384 Self::Arena => "arena",
385 })
386 .to_string()
387 }
388
389 #[must_use]
390 pub fn from_api_string(s: &str) -> Self {
391 match s.to_lowercase().as_str() {
392 "normal_aram" => Self::ARAM,
393 "one_for_all" => Self::OneForAll,
394 "pick_urf" => Self::URF,
395 "urf" => Self::ARURF,
396 "nexus_blitz" => Self::NexusBlitz,
397 "arena" => Self::Arena,
398 _ => Self::Normal,
399 }
400 }
401
402 #[must_use]
403 pub const fn all() -> &'static [Mode; 7] {
404 &[
405 Mode::Normal,
406 Mode::ARAM,
407 Mode::OneForAll,
408 Mode::URF,
409 Mode::ARURF,
410 Mode::NexusBlitz,
411 Mode::Arena,
412 ]
413 }
414}
415
416impl Display for Mode {
417 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
418 let mode_str = match self {
419 Self::Normal => "Normal",
420 Self::ARAM => "ARAM",
421 Self::OneForAll => "OneForAll",
422 Self::URF => "URF",
423 Self::ARURF => "ARURF",
424 Self::NexusBlitz => "NexusBlitz",
425 Self::Arena => "Arena",
426 };
427 write!(f, "{mode_str}")
428 }
429}
430
431impl From<&str> for Mode {
432 fn from(mode_str: &str) -> Self {
433 match mode_str.to_lowercase().as_str() {
434 "aram" | "all_random_all_mid" | "normal_aram" => Self::ARAM,
435 "oneforall" | "one_for_all" => Self::OneForAll,
436 "urf" | "ultra_rapid_fire" => Self::URF,
437 "arurf" => Self::ARURF,
438 "nexus_blitz" | "nexusblitz" => Self::NexusBlitz,
439 "arena" => Self::Arena,
440 _ => Self::Normal,
441 }
442 }
443}
444
445impl FromStr for Mode {
446 type Err = String;
447
448 fn from_str(s: &str) -> Result<Self, Self::Err> {
449 Ok(Mode::from(s))
450 }
451}
452
453#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
454pub enum Build {
455 #[default]
456 Recommended,
457 OnHit,
458 Crit,
459 Lethality,
460 AD,
461 AP,
462 Tank,
463}
464
465impl From<&str> for Build {
466 fn from(kind_str: &str) -> Self {
467 match kind_str.to_lowercase().as_str() {
468 "onhit" | "onhit-overview" => Self::OnHit,
469 "crit" | "crit-overview" => Self::Crit,
470 "lethality" | "lethality-overview" => Self::Lethality,
471 "ad" | "ad-overview" => Self::AD,
472 "ap" | "ap-overview" => Self::AP,
473 "tank" | "tank-overview" => Self::Tank,
474 _ => Self::Recommended,
475 }
476 }
477}
478
479impl FromStr for Build {
480 type Err = String;
481
482 fn from_str(s: &str) -> Result<Self, Self::Err> {
483 Ok(Build::from(s))
484 }
485}
486
487impl Display for Build {
488 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
489 let kind_str = match self {
490 Self::Recommended => "Recommended",
491 Self::OnHit => "On-Hit",
492 Self::Crit => "Crit",
493 Self::Lethality => "Lethality",
494 Self::AD => "AD",
495 Self::AP => "AP",
496 Self::Tank => "Tank",
497 };
498 write!(f, "{kind_str}")
499 }
500}
501
502impl Build {
503 #[must_use]
504 pub const fn all() -> &'static [Build; 7] {
505 &[
506 Build::Recommended,
507 Build::OnHit,
508 Build::Crit,
509 Build::Lethality,
510 Build::AD,
511 Build::AP,
512 Build::Tank,
513 ]
514 }
515
516 #[must_use]
517 pub fn to_api_string(&self) -> &'static str {
518 match self {
519 Build::Recommended => "overview",
520 Build::OnHit => "onhit-overview",
521 Build::Crit => "crit-overview",
522 Build::Lethality => "lethality-overview",
523 Build::AD => "ad-overview",
524 Build::AP => "ap-overview",
525 Build::Tank => "tank-overview",
526 }
527 }
528
529 #[must_use]
530 pub fn from_api_string(s: &str) -> Self {
531 match s.to_lowercase().as_str() {
532 "onhit-overview" => Self::OnHit,
533 "crit-overview" => Self::Crit,
534 "lethality-overview" => Self::Lethality,
535 "ad-overview" => Self::AD,
536 "ap-overview" => Self::AP,
537 "tank-overview" => Self::Tank,
538 _ => Self::Recommended,
539 }
540 }
541}
542
543#[cfg(test)]
544mod tests {
545
546 use super::*;
547
548 #[test]
549 fn test_get_role() {
550 assert_eq!(get_role("top"), Role::Top);
551 assert_eq!(get_role("mid"), Role::Mid);
552 assert_eq!(get_role("sup"), Role::Support);
553 assert_eq!(get_role("Adc"), Role::ADCarry);
554 assert_eq!(get_role("jungle"), Role::Jungle);
555 }
556}