1use std::fmt::{Display, Formatter};
4use std::sync::OnceLock;
5
6use anyhow::{anyhow, Result};
7use bitflags::bitflags;
8
9use crate::helpers::display_choices;
10
11static GAME: OnceLock<Game> = OnceLock::new();
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
18pub enum Game {
19 #[cfg(feature = "ck3")]
20 Ck3,
21 #[cfg(feature = "vic3")]
22 Vic3,
23 #[cfg(feature = "imperator")]
24 Imperator,
25}
26
27impl Game {
28 pub fn set(game: Game) -> Result<()> {
31 GAME.set(game).map_err(|_| anyhow!("tried to set game type twice"))?;
32 Ok(())
33 }
34
35 #[allow(clippy::self_named_constructors)] #[allow(unreachable_code)]
41 pub fn game() -> Game {
42 #[cfg(all(feature = "ck3", not(feature = "vic3"), not(feature = "imperator")))]
43 return Game::Ck3;
44 #[cfg(all(feature = "vic3", not(feature = "ck3"), not(feature = "imperator")))]
45 return Game::Vic3;
46 #[cfg(all(feature = "imperator", not(feature = "ck3"), not(feature = "vic3")))]
47 return Game::Imperator;
48 *GAME.get().expect("internal error: don't know which game we are validating")
49 }
50
51 pub(crate) fn is_ck3() -> bool {
53 #[cfg(not(feature = "ck3"))]
54 return false;
55 #[cfg(all(feature = "ck3", not(feature = "vic3"), not(feature = "imperator")))]
56 return true;
57 #[cfg(all(feature = "ck3", any(feature = "vic3", feature = "imperator")))]
58 return GAME.get() == Some(&Game::Ck3);
59 }
60
61 pub(crate) fn is_vic3() -> bool {
63 #[cfg(not(feature = "vic3"))]
64 return false;
65 #[cfg(all(feature = "vic3", not(feature = "ck3"), not(feature = "imperator")))]
66 return true;
67 #[cfg(all(feature = "vic3", any(feature = "ck3", feature = "imperator")))]
68 return GAME.get() == Some(&Game::Vic3);
69 }
70
71 pub(crate) fn is_imperator() -> bool {
73 #[cfg(not(feature = "imperator"))]
74 return false;
75 #[cfg(all(feature = "imperator", not(feature = "ck3"), not(feature = "vic3")))]
76 return true;
77 #[cfg(all(feature = "imperator", any(feature = "ck3", feature = "vic3")))]
78 return GAME.get() == Some(&Game::Imperator);
79 }
80}
81
82bitflags! {
83 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
88 pub struct GameFlags: u8 {
89 const Ck3 = 0x01;
90 const Vic3 = 0x02;
91 const Imperator = 0x04;
92 }
93}
94
95impl GameFlags {
96 pub fn game() -> Self {
99 match Game::game() {
101 #[cfg(feature = "ck3")]
102 Game::Ck3 => GameFlags::Ck3,
103 #[cfg(feature = "vic3")]
104 Game::Vic3 => GameFlags::Vic3,
105 #[cfg(feature = "imperator")]
106 Game::Imperator => GameFlags::Imperator,
107 }
108 }
109}
110
111impl Display for GameFlags {
112 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
113 let mut vec = Vec::new();
114 if self.contains(Self::Ck3) {
115 vec.push("Crusader Kings 3");
116 }
117 if self.contains(Self::Vic3) {
118 vec.push("Victoria 3");
119 }
120 if self.contains(Self::Imperator) {
121 vec.push("Imperator: Rome");
122 }
123 display_choices(f, &vec, "and")
124 }
125}
126
127impl From<Game> for GameFlags {
128 fn from(game: Game) -> Self {
130 match game {
131 #[cfg(feature = "ck3")]
132 Game::Ck3 => GameFlags::Ck3,
133 #[cfg(feature = "vic3")]
134 Game::Vic3 => GameFlags::Vic3,
135 #[cfg(feature = "imperator")]
136 Game::Imperator => GameFlags::Imperator,
137 }
138 }
139}