vx_core/
platform.rs

1//! Platform detection and utilities
2
3use serde::{Deserialize, Serialize};
4
5/// Supported operating systems
6#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
7pub enum OperatingSystem {
8    Windows,
9    MacOS,
10    Linux,
11    FreeBSD,
12    Other(String),
13}
14
15/// Supported CPU architectures
16#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
17pub enum Architecture {
18    X86_64,
19    X86,
20    Aarch64,
21    Arm,
22    Other(String),
23}
24
25/// Platform information
26#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
27pub struct Platform {
28    pub os: OperatingSystem,
29    pub arch: Architecture,
30}
31
32impl Platform {
33    /// Get the current platform
34    pub fn current() -> Self {
35        Self {
36            os: Self::current_os(),
37            arch: Self::current_arch(),
38        }
39    }
40
41    /// Get the current operating system
42    pub fn current_os() -> OperatingSystem {
43        if cfg!(target_os = "windows") {
44            OperatingSystem::Windows
45        } else if cfg!(target_os = "macos") {
46            OperatingSystem::MacOS
47        } else if cfg!(target_os = "linux") {
48            OperatingSystem::Linux
49        } else if cfg!(target_os = "freebsd") {
50            OperatingSystem::FreeBSD
51        } else {
52            OperatingSystem::Other(std::env::consts::OS.to_string())
53        }
54    }
55
56    /// Get the current architecture
57    pub fn current_arch() -> Architecture {
58        if cfg!(target_arch = "x86_64") {
59            Architecture::X86_64
60        } else if cfg!(target_arch = "x86") {
61            Architecture::X86
62        } else if cfg!(target_arch = "aarch64") {
63            Architecture::Aarch64
64        } else if cfg!(target_arch = "arm") {
65            Architecture::Arm
66        } else {
67            Architecture::Other(std::env::consts::ARCH.to_string())
68        }
69    }
70
71    /// Get platform string for Node.js downloads
72    pub fn node_platform_string(&self) -> Option<(String, String)> {
73        let os = match self.os {
74            OperatingSystem::Windows => "win",
75            OperatingSystem::MacOS => "darwin",
76            OperatingSystem::Linux => "linux",
77            _ => return None,
78        };
79
80        let arch = match self.arch {
81            Architecture::X86_64 => "x64",
82            Architecture::X86 => "x86",
83            Architecture::Aarch64 => "arm64",
84            _ => return None,
85        };
86
87        Some((os.to_string(), arch.to_string()))
88    }
89
90    /// Get platform string for Go downloads
91    pub fn go_platform_string(&self) -> Option<(String, String)> {
92        let os = match self.os {
93            OperatingSystem::Windows => "windows",
94            OperatingSystem::MacOS => "darwin",
95            OperatingSystem::Linux => "linux",
96            OperatingSystem::FreeBSD => "freebsd",
97            _ => return None,
98        };
99
100        let arch = match self.arch {
101            Architecture::X86_64 => "amd64",
102            Architecture::X86 => "386",
103            Architecture::Aarch64 => "arm64",
104            Architecture::Arm => "armv6l",
105            _ => return None,
106        };
107
108        Some((os.to_string(), arch.to_string()))
109    }
110
111    /// Get file extension for archives on this platform
112    pub fn archive_extension(&self) -> &'static str {
113        match self.os {
114            OperatingSystem::Windows => "zip",
115            _ => "tar.gz",
116        }
117    }
118
119    /// Get executable extension for this platform
120    pub fn executable_extension(&self) -> &'static str {
121        match self.os {
122            OperatingSystem::Windows => "exe",
123            _ => "",
124        }
125    }
126}
127
128impl std::fmt::Display for OperatingSystem {
129    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
130        match self {
131            OperatingSystem::Windows => write!(f, "windows"),
132            OperatingSystem::MacOS => write!(f, "macos"),
133            OperatingSystem::Linux => write!(f, "linux"),
134            OperatingSystem::FreeBSD => write!(f, "freebsd"),
135            OperatingSystem::Other(s) => write!(f, "{}", s),
136        }
137    }
138}
139
140impl std::fmt::Display for Architecture {
141    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
142        match self {
143            Architecture::X86_64 => write!(f, "x86_64"),
144            Architecture::X86 => write!(f, "x86"),
145            Architecture::Aarch64 => write!(f, "aarch64"),
146            Architecture::Arm => write!(f, "arm"),
147            Architecture::Other(s) => write!(f, "{}", s),
148        }
149    }
150}
151
152impl std::fmt::Display for Platform {
153    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
154        write!(f, "{}-{}", self.os, self.arch)
155    }
156}
157
158#[cfg(test)]
159mod tests {
160    use super::*;
161
162    #[test]
163    fn test_current_platform() {
164        let platform = Platform::current();
165
166        // Should detect some valid OS and arch
167        assert!(!matches!(platform.os, OperatingSystem::Other(_)));
168        assert!(!matches!(platform.arch, Architecture::Other(_)));
169    }
170
171    #[test]
172    fn test_platform_strings() {
173        let platform = Platform::current();
174
175        // Should be able to generate platform strings for major tools
176        if matches!(
177            platform.os,
178            OperatingSystem::Windows | OperatingSystem::MacOS | OperatingSystem::Linux
179        ) {
180            assert!(platform.node_platform_string().is_some());
181            assert!(platform.go_platform_string().is_some());
182        }
183    }
184
185    #[test]
186    fn test_extensions() {
187        let platform = Platform::current();
188
189        let archive_ext = platform.archive_extension();
190        let _exe_ext = platform.executable_extension();
191
192        assert!(!archive_ext.is_empty());
193        // exe_ext can be empty on Unix systems
194    }
195}