use camino::Utf8PathBuf;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum Os {
MacOs,
Linux,
Windows,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum Arch {
X64,
Arm64,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum Platform {
MacosArm64,
MacosX64,
LinuxX64,
LinuxArm64,
WindowsX64,
}
impl Platform {
pub const ALL: [Platform; 5] = [
Platform::MacosArm64,
Platform::MacosX64,
Platform::LinuxX64,
Platform::LinuxArm64,
Platform::WindowsX64,
];
pub fn id(self) -> &'static str {
match self {
Platform::MacosArm64 => "darwin-arm64",
Platform::MacosX64 => "darwin-x64",
Platform::LinuxX64 => "linux-x64",
Platform::LinuxArm64 => "linux-arm64",
Platform::WindowsX64 => "windows-x64",
}
}
pub fn from_id(s: &str) -> Option<Platform> {
Platform::ALL.into_iter().find(|p| p.id() == s)
}
pub fn os(self) -> Os {
match self {
Platform::MacosArm64 | Platform::MacosX64 => Os::MacOs,
Platform::LinuxX64 | Platform::LinuxArm64 => Os::Linux,
Platform::WindowsX64 => Os::Windows,
}
}
pub fn arch(self) -> Arch {
match self {
Platform::MacosArm64 | Platform::LinuxArm64 => Arch::Arm64,
Platform::MacosX64 | Platform::LinuxX64 | Platform::WindowsX64 => Arch::X64,
}
}
pub fn rust_target(self) -> &'static str {
match self {
Platform::MacosArm64 => "aarch64-apple-darwin",
Platform::MacosX64 => "x86_64-apple-darwin",
Platform::LinuxX64 => "x86_64-unknown-linux-gnu",
Platform::LinuxArm64 => "aarch64-unknown-linux-gnu",
Platform::WindowsX64 => "x86_64-pc-windows-msvc",
}
}
pub fn from_rust_target(triple: &str) -> Option<Platform> {
Platform::ALL
.into_iter()
.find(|p| p.rust_target() == triple)
}
pub fn lib_prefix(self) -> &'static str {
match self.os() {
Os::MacOs | Os::Linux => "lib",
Os::Windows => "",
}
}
pub fn lib_extension(self) -> &'static str {
match self.os() {
Os::MacOs => "dylib",
Os::Linux => "so",
Os::Windows => "dll",
}
}
pub fn lib_filename(self, base: &str) -> String {
format!("{}{base}.{}", self.lib_prefix(), self.lib_extension())
}
pub fn nuget_rid(self) -> &'static str {
match self {
Platform::MacosArm64 => "osx-arm64",
Platform::MacosX64 => "osx-x64",
Platform::LinuxX64 => "linux-x64",
Platform::LinuxArm64 => "linux-arm64",
Platform::WindowsX64 => "win-x64",
}
}
pub fn node_os(self) -> &'static str {
match self.os() {
Os::MacOs => "darwin",
Os::Linux => "linux",
Os::Windows => "win32",
}
}
pub fn node_cpu(self) -> &'static str {
match self.arch() {
Arch::Arm64 => "arm64",
Arch::X64 => "x64",
}
}
pub fn python_platform_tag(self) -> &'static str {
match self {
Platform::MacosArm64 => "macosx_11_0_arm64",
Platform::MacosX64 => "macosx_10_12_x86_64",
Platform::LinuxX64 => "manylinux2014_x86_64",
Platform::LinuxArm64 => "manylinux2014_aarch64",
Platform::WindowsX64 => "win_amd64",
}
}
pub fn ruby_platform(self) -> &'static str {
match self {
Platform::MacosArm64 => "arm64-darwin",
Platform::MacosX64 => "x86_64-darwin",
Platform::LinuxX64 => "x86_64-linux",
Platform::LinuxArm64 => "aarch64-linux",
Platform::WindowsX64 => "x64-mingw-ucrt",
}
}
pub fn display_name(self) -> &'static str {
match self {
Platform::MacosArm64 => "macOS arm64",
Platform::MacosX64 => "macOS x64",
Platform::LinuxX64 => "Linux x64",
Platform::LinuxArm64 => "Linux arm64",
Platform::WindowsX64 => "Windows x64",
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct NativeBinary {
pub platform: Platform,
pub source: Utf8PathBuf,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct BinarySet {
pub lib_name: String,
pub binaries: Vec<NativeBinary>,
}
impl BinarySet {
pub fn new(lib_name: impl Into<String>) -> Self {
Self {
lib_name: lib_name.into(),
binaries: Vec::new(),
}
}
pub fn insert(&mut self, platform: Platform, source: impl Into<Utf8PathBuf>) {
let source = source.into();
if let Some(existing) = self.binaries.iter_mut().find(|b| b.platform == platform) {
existing.source = source;
} else {
self.binaries.push(NativeBinary { platform, source });
}
}
pub fn get(&self, platform: Platform) -> Option<&NativeBinary> {
self.binaries.iter().find(|b| b.platform == platform)
}
pub fn platforms(&self) -> impl Iterator<Item = Platform> + '_ {
self.binaries.iter().map(|b| b.platform)
}
pub fn is_empty(&self) -> bool {
self.binaries.is_empty()
}
pub fn bundled_filename(&self, platform: Platform) -> String {
platform.lib_filename(&self.lib_name)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn ids_round_trip() {
for p in Platform::ALL {
assert_eq!(Platform::from_id(p.id()), Some(p));
}
assert_eq!(Platform::from_id("nonsense"), None);
}
#[test]
fn rust_targets_round_trip() {
for p in Platform::ALL {
assert_eq!(Platform::from_rust_target(p.rust_target()), Some(p));
}
assert_eq!(Platform::from_rust_target("mips-unknown-linux-gnu"), None);
}
#[test]
fn lib_filenames_are_platform_correct() {
assert_eq!(
Platform::MacosArm64.lib_filename("contacts"),
"libcontacts.dylib"
);
assert_eq!(
Platform::LinuxX64.lib_filename("contacts"),
"libcontacts.so"
);
assert_eq!(
Platform::WindowsX64.lib_filename("contacts"),
"contacts.dll"
);
}
#[test]
fn ecosystem_identifiers() {
assert_eq!(Platform::MacosArm64.nuget_rid(), "osx-arm64");
assert_eq!(Platform::WindowsX64.nuget_rid(), "win-x64");
assert_eq!(Platform::MacosX64.node_os(), "darwin");
assert_eq!(Platform::MacosX64.node_cpu(), "x64");
assert_eq!(Platform::WindowsX64.node_os(), "win32");
assert_eq!(
Platform::LinuxArm64.python_platform_tag(),
"manylinux2014_aarch64"
);
assert_eq!(Platform::MacosArm64.ruby_platform(), "arm64-darwin");
assert_eq!(Platform::LinuxX64.ruby_platform(), "x86_64-linux");
}
#[test]
fn binary_set_insert_get_and_replace() {
let mut set = BinarySet::new("contacts");
assert!(set.is_empty());
set.insert(Platform::MacosArm64, "/tmp/a/libcontacts.dylib");
set.insert(Platform::LinuxX64, "/tmp/b/libcontacts.so");
assert_eq!(set.binaries.len(), 2);
set.insert(Platform::MacosArm64, "/tmp/c/libcontacts.dylib");
assert_eq!(set.binaries.len(), 2);
assert_eq!(
set.get(Platform::MacosArm64).unwrap().source.as_str(),
"/tmp/c/libcontacts.dylib"
);
let platforms: Vec<Platform> = set.platforms().collect();
assert_eq!(platforms, vec![Platform::MacosArm64, Platform::LinuxX64]);
assert_eq!(set.bundled_filename(Platform::WindowsX64), "contacts.dll");
}
}