pub fn current_platform() -> &'static str {
match (std::env::consts::OS, std::env::consts::ARCH) {
("macos", "aarch64") => "darwin-aarch64",
("macos", "x86_64") => "darwin-x86_64",
("linux", "aarch64") => "linux-aarch64",
("linux", "x86_64") => "linux-x86_64",
_ => "unknown",
}
}
pub const SUPPORTED_PLATFORMS: [&str; 4] = [
"darwin-aarch64",
"darwin-x86_64",
"linux-aarch64",
"linux-x86_64",
];
#[must_use]
pub fn split_platform_tag(platform: &str) -> Option<(&str, &str)> {
let (os, arch) = platform.split_once('-')?;
if os.trim().is_empty() || arch.trim().is_empty() {
return None;
}
Some((os, arch))
}
#[must_use]
pub fn split_platform_suffix(file_name: &str) -> Option<(&str, &'static str)> {
let stem = file_name.strip_suffix(".mur.zip")?;
SUPPORTED_PLATFORMS.iter().find_map(|platform| {
stem.strip_suffix(platform)
.and_then(|head| head.strip_suffix('-'))
.filter(|head| !head.is_empty())
.map(|head| (head, *platform))
})
}
pub const DARWIN_ANY_ARCH: &str = "darwin";
pub fn binary_platform(bytes: &[u8]) -> Option<&'static str> {
if bytes.starts_with(b"\x7fELF") {
return elf_platform(bytes);
}
if bytes.starts_with(&[0xCA, 0xFE, 0xBA, 0xBE]) {
return Some(DARWIN_ANY_ARCH);
}
macho_platform(bytes)
}
fn elf_platform(bytes: &[u8]) -> Option<&'static str> {
if bytes.len() < 64 {
return None;
}
if bytes[4] != 2 {
return None;
}
let le = match bytes[5] {
1 => true,
2 => false,
_ => return None,
};
let raw = [bytes[18], bytes[19]];
let e_machine = if le {
u16::from_le_bytes(raw)
} else {
u16::from_be_bytes(raw)
};
match e_machine {
0x3E => Some("linux-x86_64"), 0xB7 => Some("linux-aarch64"), _ => None,
}
}
fn macho_platform(bytes: &[u8]) -> Option<&'static str> {
let magic = u32::from_le_bytes(bytes.get(0..4)?.try_into().ok()?);
let le = match magic {
0xFEED_FACF => true, 0xCFFA_EDFE => false,
_ => return None,
};
let raw: [u8; 4] = bytes.get(4..8)?.try_into().ok()?;
let cputype = if le {
i32::from_le_bytes(raw)
} else {
i32::from_be_bytes(raw)
};
match cputype {
0x0100_0007 => Some("darwin-x86_64"), 0x0100_000C => Some("darwin-aarch64"), _ => None,
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum NativeBinaryVerdict {
Runnable,
Indeterminate,
Mismatch { binary_platform: &'static str },
}
pub fn native_binary_verdict(bytes: &[u8], host_platform: &str) -> NativeBinaryVerdict {
let Some(binary_platform) = binary_platform(bytes) else {
return NativeBinaryVerdict::Indeterminate;
};
if host_platform == "unknown" {
return NativeBinaryVerdict::Indeterminate;
}
if binary_platform == host_platform {
return NativeBinaryVerdict::Runnable;
}
if binary_platform == DARWIN_ANY_ARCH && host_platform.starts_with("darwin-") {
return NativeBinaryVerdict::Runnable;
}
NativeBinaryVerdict::Mismatch { binary_platform }
}
#[cfg(test)]
mod tests {
#[test]
fn known_platforms_all_have_canonical_strings() {
let cases = [
("macos", "aarch64", "darwin-aarch64"),
("macos", "x86_64", "darwin-x86_64"),
("linux", "aarch64", "linux-aarch64"),
("linux", "x86_64", "linux-x86_64"),
];
for (os, arch, expected) in cases {
let result = map_platform(os, arch);
assert_eq!(result, expected, "os={os} arch={arch}");
}
}
#[test]
fn unknown_os_arch_returns_unknown() {
assert_eq!(map_platform("windows", "x86_64"), "unknown");
assert_eq!(map_platform("freebsd", "aarch64"), "unknown");
assert_eq!(map_platform("", ""), "unknown");
}
use super::{split_platform_suffix, split_platform_tag, SUPPORTED_PLATFORMS};
use std::collections::BTreeSet;
#[test]
fn supported_platforms_matches_what_current_platform_returns() {
let produced: BTreeSet<&str> = ["macos", "linux", "windows", "freebsd"]
.into_iter()
.flat_map(|os| {
["aarch64", "x86_64", "riscv64"]
.into_iter()
.map(move |arch| map_platform(os, arch))
})
.filter(|platform| *platform != "unknown")
.collect();
let declared: BTreeSet<&str> = SUPPORTED_PLATFORMS.into_iter().collect();
assert_eq!(produced, declared);
assert_eq!(SUPPORTED_PLATFORMS.len(), declared.len(), "duplicate tag");
}
#[test]
fn this_host_is_a_supported_platform_or_unknown() {
let host = super::current_platform();
assert!(
host == "unknown" || SUPPORTED_PLATFORMS.contains(&host),
"current_platform() returned {host}, which SUPPORTED_PLATFORMS does not list"
);
}
#[test]
fn platform_tag_splits_into_os_and_arch() {
assert_eq!(
split_platform_tag("linux-x86_64"),
Some(("linux", "x86_64"))
);
assert_eq!(
split_platform_tag("darwin-aarch64"),
Some(("darwin", "aarch64"))
);
assert_eq!(split_platform_tag("linux"), None);
assert_eq!(split_platform_tag("-x86_64"), None);
assert_eq!(split_platform_tag("linux-"), None);
}
#[test]
fn platform_suffix_splits_off_a_recognised_tag() {
for platform in SUPPORTED_PLATFORMS {
assert_eq!(
split_platform_suffix(&format!("nativetool-0.1.0-{platform}.mur.zip")),
Some(("nativetool-0.1.0", platform))
);
}
}
#[test]
fn an_untagged_or_unrecognised_name_carries_no_platform() {
assert_eq!(split_platform_suffix("wasmtool-0.1.0.mur.zip"), None);
assert_eq!(split_platform_suffix("wasmtool.mur.zip"), None);
assert_eq!(
split_platform_suffix("tool-0.1.0-windows-x86_64.mur.zip"),
None
);
assert_eq!(
split_platform_suffix("tool-0.1.0-linux-riscv64.mur.zip"),
None
);
assert_eq!(split_platform_suffix("linux-x86_64.mur.zip"), None);
assert_eq!(split_platform_suffix("toollinux-x86_64.mur.zip"), None);
assert_eq!(
split_platform_suffix("tool-0.1.0-linux-x86_64.sha256"),
None
);
assert_eq!(split_platform_suffix("tool-0.1.0-linux-x86_64.zip"), None);
}
use super::{binary_platform, native_binary_verdict, NativeBinaryVerdict, DARWIN_ANY_ARCH};
fn elf64(le: bool, e_machine: u16) -> Vec<u8> {
let mut bytes = vec![0u8; 64];
bytes[0..4].copy_from_slice(b"\x7fELF");
bytes[4] = 2; bytes[5] = if le { 1 } else { 2 };
let machine = if le {
e_machine.to_le_bytes()
} else {
e_machine.to_be_bytes()
};
bytes[18..20].copy_from_slice(&machine);
bytes
}
fn macho64(le: bool, cputype: i32) -> Vec<u8> {
let mut bytes = vec![0u8; 32];
let magic: u32 = 0xFEED_FACF;
let (magic_bytes, cpu_bytes) = if le {
(magic.to_le_bytes(), cputype.to_le_bytes())
} else {
(magic.to_be_bytes(), cputype.to_be_bytes())
};
bytes[0..4].copy_from_slice(&magic_bytes);
bytes[4..8].copy_from_slice(&cpu_bytes);
bytes
}
#[test]
fn elf64_machines_map_to_linux_platforms() {
assert_eq!(binary_platform(&elf64(true, 0x3E)), Some("linux-x86_64"));
assert_eq!(binary_platform(&elf64(true, 0xB7)), Some("linux-aarch64"));
}
#[test]
fn elf64_big_endian_reads_e_machine_in_that_order() {
assert_eq!(binary_platform(&elf64(false, 0x3E)), Some("linux-x86_64"));
assert_eq!(binary_platform(&elf64(false, 0xB7)), Some("linux-aarch64"));
let mut mislabelled = elf64(true, 0x3E);
mislabelled[5] = 2;
assert_eq!(binary_platform(&mislabelled), None);
}
#[test]
fn macho64_cputypes_map_to_darwin_platforms_in_both_byte_orders() {
for le in [true, false] {
assert_eq!(
binary_platform(&macho64(le, 0x0100_0007)),
Some("darwin-x86_64"),
"le={le}"
);
assert_eq!(
binary_platform(&macho64(le, 0x0100_000C)),
Some("darwin-aarch64"),
"le={le}"
);
}
}
#[test]
fn fat_macho_is_darwin_with_no_architecture() {
let mut bytes = vec![0u8; 32];
bytes[0..4].copy_from_slice(&[0xCA, 0xFE, 0xBA, 0xBE]);
assert_eq!(binary_platform(&bytes), Some(DARWIN_ANY_ARCH));
assert_eq!(DARWIN_ANY_ARCH, "darwin");
}
#[test]
fn unidentifiable_images_are_none() {
let mut elf32 = elf64(true, 0x3E);
elf32[4] = 1;
assert_eq!(binary_platform(&elf32), None);
assert_eq!(binary_platform(&elf64(true, 0x3E)[..20]), None);
assert_eq!(binary_platform(&elf64(true, 0xF3)), None);
assert_eq!(binary_platform(&macho64(true, 0x0100_0012)), None);
assert_eq!(binary_platform(b"#!/bin/sh\nexit 0\n"), None);
assert_eq!(binary_platform(b"\0asm\x01\0\0\0"), None);
assert_eq!(binary_platform(b""), None);
}
#[test]
fn verdict_matches_host_platform() {
assert_eq!(
native_binary_verdict(&elf64(true, 0x3E), "linux-x86_64"),
NativeBinaryVerdict::Runnable
);
assert_eq!(
native_binary_verdict(&macho64(true, 0x0100_000C), "darwin-aarch64"),
NativeBinaryVerdict::Runnable
);
}
#[test]
fn verdict_reports_architecture_mismatch_within_one_os() {
assert_eq!(
native_binary_verdict(&elf64(true, 0x3E), "linux-aarch64"),
NativeBinaryVerdict::Mismatch {
binary_platform: "linux-x86_64"
}
);
assert_eq!(
native_binary_verdict(&macho64(true, 0x0100_0007), "darwin-aarch64"),
NativeBinaryVerdict::Mismatch {
binary_platform: "darwin-x86_64"
}
);
}
#[test]
fn verdict_reports_operating_system_mismatch() {
assert_eq!(
native_binary_verdict(&macho64(true, 0x0100_000C), "linux-aarch64"),
NativeBinaryVerdict::Mismatch {
binary_platform: "darwin-aarch64"
}
);
assert_eq!(
native_binary_verdict(&elf64(true, 0xB7), "darwin-aarch64"),
NativeBinaryVerdict::Mismatch {
binary_platform: "linux-aarch64"
}
);
}
#[test]
fn fat_macho_runs_on_any_darwin_host_and_no_linux_one() {
let mut fat = vec![0u8; 32];
fat[0..4].copy_from_slice(&[0xCA, 0xFE, 0xBA, 0xBE]);
assert_eq!(
native_binary_verdict(&fat, "darwin-aarch64"),
NativeBinaryVerdict::Runnable
);
assert_eq!(
native_binary_verdict(&fat, "darwin-x86_64"),
NativeBinaryVerdict::Runnable
);
assert_eq!(
native_binary_verdict(&fat, "linux-x86_64"),
NativeBinaryVerdict::Mismatch {
binary_platform: DARWIN_ANY_ARCH
}
);
}
#[test]
fn unidentified_image_or_unknown_host_is_never_a_mismatch() {
assert_eq!(
native_binary_verdict(b"#!/bin/sh\nexit 0\n", "linux-x86_64"),
NativeBinaryVerdict::Indeterminate
);
assert_eq!(
native_binary_verdict(&elf64(true, 0x3E), "unknown"),
NativeBinaryVerdict::Indeterminate
);
}
fn map_platform(os: &str, arch: &str) -> &'static str {
match (os, arch) {
("macos", "aarch64") => "darwin-aarch64",
("macos", "x86_64") => "darwin-x86_64",
("linux", "aarch64") => "linux-aarch64",
("linux", "x86_64") => "linux-x86_64",
_ => "unknown",
}
}
}