Skip to main content

vanta_core/
platform.rs

1//! Platform identifiers — the canonical `os/arch[/libc]` tokens.
2//!
3//! See `docs/17-cross-platform.md` and `docs/26-registry-and-metadata-reference.md`.
4
5use crate::error::{Area, VtaError, VtaResult};
6use std::fmt;
7
8/// Operating system.
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
10#[non_exhaustive]
11pub enum Os {
12    Linux,
13    Macos,
14    Windows,
15}
16
17/// CPU architecture.
18#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
19#[non_exhaustive]
20pub enum Arch {
21    X86_64,
22    Aarch64,
23}
24
25/// C library / ABI variant (only meaningful on Linux).
26#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
27#[non_exhaustive]
28pub enum Libc {
29    Gnu,
30    Musl,
31    /// Not applicable (macOS / Windows).
32    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/// A fully-qualified target platform.
65#[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    /// The canonical token, e.g. `"linux/x86_64/gnu"` or `"macos/aarch64"`.
74    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    /// Parse a canonical token. Linux requires a libc segment; others must omit it.
83    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    /// The platform the running binary was built for.
110    ///
111    /// On Linux this reports the `gnu` libc; musl targets are distinguished at
112    /// artifact-selection time (see `docs/17-cross-platform.md`).
113    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}