1use serde::{Deserialize, Serialize};
4
5#[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#[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#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
27pub struct Platform {
28 pub os: OperatingSystem,
29 pub arch: Architecture,
30}
31
32impl Platform {
33 pub fn current() -> Self {
35 Self {
36 os: Self::current_os(),
37 arch: Self::current_arch(),
38 }
39 }
40
41 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 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 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 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 pub fn archive_extension(&self) -> &'static str {
113 match self.os {
114 OperatingSystem::Windows => "zip",
115 _ => "tar.gz",
116 }
117 }
118
119 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 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 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 }
195}