1use crate::error::{Area, VtaError, VtaResult};
6use std::fmt;
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
10#[non_exhaustive]
11pub enum Os {
12 Linux,
13 Macos,
14 Windows,
15}
16
17#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
19#[non_exhaustive]
20pub enum Arch {
21 X86_64,
22 Aarch64,
23}
24
25#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
27#[non_exhaustive]
28pub enum Libc {
29 Gnu,
30 Musl,
31 None,
33}
34
35impl Os {
36 pub fn as_str(self) -> &'static str {
37 match self {
38 Os::Linux => "linux",
39 Os::Macos => "macos",
40 Os::Windows => "windows",
41 }
42 }
43}
44
45impl Arch {
46 pub fn as_str(self) -> &'static str {
47 match self {
48 Arch::X86_64 => "x86_64",
49 Arch::Aarch64 => "aarch64",
50 }
51 }
52}
53
54impl Libc {
55 pub fn as_str(self) -> &'static str {
56 match self {
57 Libc::Gnu => "gnu",
58 Libc::Musl => "musl",
59 Libc::None => "",
60 }
61 }
62}
63
64#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
66pub struct Platform {
67 pub os: Os,
68 pub arch: Arch,
69 pub libc: Libc,
70}
71
72impl Platform {
73 pub fn token(&self) -> String {
75 let base = format!("{}/{}", self.os.as_str(), self.arch.as_str());
76 match self.libc {
77 Libc::None => base,
78 other => format!("{base}/{}", other.as_str()),
79 }
80 }
81
82 pub fn parse(s: &str) -> VtaResult<Platform> {
84 let mut parts = s.split('/');
85 let os = match parts.next() {
86 Some("linux") => Os::Linux,
87 Some("macos") => Os::Macos,
88 Some("windows") => Os::Windows,
89 _ => return Err(bad(s)),
90 };
91 let arch = match parts.next() {
92 Some("x86_64") => Arch::X86_64,
93 Some("aarch64") => Arch::Aarch64,
94 _ => return Err(bad(s)),
95 };
96 let libc = match (os, parts.next()) {
97 (Os::Linux, Some("gnu")) => Libc::Gnu,
98 (Os::Linux, Some("musl")) => Libc::Musl,
99 (Os::Linux, _) => return Err(bad(s)),
100 (_, None) => Libc::None,
101 (_, Some(_)) => return Err(bad(s)),
102 };
103 if parts.next().is_some() {
104 return Err(bad(s));
105 }
106 Ok(Platform { os, arch, libc })
107 }
108
109 pub fn current() -> Platform {
114 let os = if cfg!(target_os = "macos") {
115 Os::Macos
116 } else if cfg!(target_os = "windows") {
117 Os::Windows
118 } else {
119 Os::Linux
120 };
121 let arch = if cfg!(target_arch = "aarch64") {
122 Arch::Aarch64
123 } else {
124 Arch::X86_64
125 };
126 let libc = match os {
127 Os::Linux => Libc::Gnu,
128 _ => Libc::None,
129 };
130 Platform { os, arch, libc }
131 }
132}
133
134impl fmt::Display for Platform {
135 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
136 f.write_str(&self.token())
137 }
138}
139
140fn bad(s: &str) -> VtaError {
141 VtaError::new(Area::Sys, 1, format!("unknown platform token `{s}`"))
142}