pacenotes_installer/
gamedir.rs1#[derive(Clone, Copy, PartialEq, Eq, Debug)]
6pub enum Game {
7 Rbr,
8 DirtRally2,
9 AssettoCorsa,
10 BeamNg,
11}
12
13impl Game {
14 pub const ALL: [Game; 4] = [
16 Game::Rbr,
17 Game::DirtRally2,
18 Game::AssettoCorsa,
19 Game::BeamNg,
20 ];
21
22 pub fn title(self) -> &'static str {
24 match self {
25 Game::Rbr => "Richard Burns Rally",
26 Game::DirtRally2 => "Dirt Rally 2.0",
27 Game::AssettoCorsa => "Assetto Corsa",
28 Game::BeamNg => "BeamNG",
29 }
30 }
31
32 pub fn marker(self) -> &'static str {
35 match self {
36 Game::Rbr => "RichardBurnsRally_SSE.exe",
37 Game::DirtRally2 => "dirtrally2.exe",
38 Game::AssettoCorsa => "assettocorsa.exe",
39 Game::BeamNg => "BeamNG.drive.exe",
40 }
41 }
42
43 pub fn id(self) -> &'static str {
45 match self {
46 Game::Rbr => pacenotes_shared::GAME_RBR,
47 Game::DirtRally2 => pacenotes_shared::GAME_DIRT_RALLY2,
48 Game::AssettoCorsa => pacenotes_shared::GAME_ASSETTOCORSA,
49 Game::BeamNg => pacenotes_shared::GAME_BEAMNG,
50 }
51 }
52
53 pub fn from_id(id: &str) -> Option<Game> {
55 Game::ALL.iter().copied().find(|game| game.id() == id)
56 }
57
58 pub fn index(self) -> usize {
59 Game::ALL.iter().position(|&game| game == self).unwrap_or(0)
60 }
61
62 pub fn from_index(index: usize) -> Game {
64 Game::ALL.get(index).copied().unwrap_or(Game::Rbr)
65 }
66}
67
68#[derive(Clone, Copy, PartialEq, Eq, Debug)]
70pub enum DirStatus {
71 Empty,
72 NotFound,
74 NotGame,
76 Ok,
77}
78
79impl DirStatus {
80 pub fn is_ok(self) -> bool {
81 self == DirStatus::Ok
82 }
83}
84
85pub fn detect(dir: &str) -> Vec<Game> {
90 let trimmed = dir.trim();
91 if trimmed.is_empty() {
92 return Vec::new();
93 }
94 let Ok(entries) = std::fs::read_dir(trimmed) else {
95 return Vec::new();
96 };
97
98 let file_names: Vec<String> = entries
99 .flatten()
100 .filter(|entry| entry.file_type().is_ok_and(|file_type| file_type.is_file()))
101 .map(|entry| entry.file_name().to_string_lossy().to_lowercase())
102 .collect();
103
104 Game::ALL
105 .iter()
106 .copied()
107 .filter(|game| file_names.contains(&game.marker().to_lowercase()))
108 .collect()
109}
110
111pub fn validate(game: Game, dir: &str) -> DirStatus {
113 let trimmed = dir.trim();
114 if trimmed.is_empty() {
115 return DirStatus::Empty;
116 }
117 if !std::path::Path::new(trimmed).is_dir() {
118 return DirStatus::NotFound;
119 }
120 if detect(trimmed).contains(&game) {
121 DirStatus::Ok
122 } else {
123 DirStatus::NotGame
124 }
125}
126
127#[cfg(test)]
128mod tests;