Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/znippy

plugins/native/znippy-plugin-elf/src/claim.rs

//! What the **path** claims about a binary's architecture — and nothing else.
//!
//! This is the one place in the crate that looks at a file name, and it exists
//! for exactly one query: **"which members lie about their architecture"**. A
//! path is a *claim*; the ELF header is the *fact* (law **E-0**,
//! `.nornir/elf-design.md` §2). Nothing here is ever written into a column that
//! states a fact — [`arch_claim`] fills the column literally called
//! `arch_claim`, and [`lies`] compares it against what the header actually said.
//!
//! Unconditional and dependency-free (pure `&str` -> `&str`), like the sibling
//! plugins' `member` module, so `--no-default-features` compiles for
//! `wasm32-unknown-unknown`.

/// Split a path into its tokens: `/`, `\`, `.` and `-` are separators.
///
/// `_` is **not** a separator, and that is load-bearing: splitting on it turns
/// `x86_64-unknown-linux-gnu` into `x86` + `64`, and `x86` is a *different*
/// architecture. A 64-bit triple read as a 32-bit claim would have made this
/// module manufacture the very lie it exists to detect.
fn tokens(path: &str) -> impl Iterator<Item = &str> {
    path.split(['/', '\\', '.', '-'])
}

/// The architecture a *path* claims, canonicalised to the same vocabulary
/// [`crate::facts::machine_name`] writes into `elf_machine`.
///
/// `None` = the path claims nothing, which is not a lie.
///
/// Recognises the tokens that appear in a cargo target-triple directory
/// (`target/x86_64-unknown-linux-gnu/release/…`), in an artifact directory
/// (`…/aarch64/…`) and in a package file name (`gunnar-1.4.0.aarch64.rpm`).
pub fn arch_claim(path: &str) -> Option<&'static str> {
    let mut found: Option<&'static str> = None;
    for t in tokens(path) {
        let canon = match t {
            "x86" | "i386" | "i486" | "i586" | "i686" => "x86",
            "x86_64" | "amd64" | "x64" => "x86-64",
            "aarch64" | "arm64" => "aarch64",
            "armv7" | "armv7l" | "armv6" | "arm" | "armhf" | "armel" => "arm",
            "riscv64" | "riscv64gc" => "riscv64",
            "ppc64le" | "powerpc64le" | "ppc64" | "powerpc64" => "powerpc64",
            "s390x" => "s390x",
            "loongarch64" => "loongarch64",
            "mips64el" | "mips64" => "mips64",
            _ => continue,
        };
        match found {
            // Two DIFFERENT architectures in one path is not a claim we can act
            // on — it is ambiguous, and an ambiguous claim is no claim. Saying
            // "this path claims x86-64" about `.../x86_64/.../aarch64/...`
            // would itself be the guess this module exists to prevent.
            Some(prev) if prev != canon => return None,
            _ => found = Some(canon),
        }
    }
    found
}

/// Does the path's claim contradict the header's fact?
///
/// `false` when the path claimed nothing — that is silence, not a lie.
pub fn lies(claim: Option<&str>, machine: &str) -> bool {
    match claim {
        None => false,
        Some(c) => c != machine,
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn a_cargo_target_triple_directory_is_a_claim() {
        assert_eq!(arch_claim("target/x86_64-unknown-linux-gnu/release/gunnar"), Some("x86-64"));
        assert_eq!(arch_claim("target/aarch64-unknown-linux-musl/release/holger"), Some("aarch64"));
    }

    #[test]
    fn a_bare_arch_directory_is_a_claim() {
        assert_eq!(arch_claim("artifacts/aarch64/bin/korp"), Some("aarch64"));
        assert_eq!(arch_claim("rpm/gunnar.riscv64gc.rpm"), Some("riscv64"));
    }

    #[test]
    fn a_path_that_claims_nothing_is_not_a_lie() {
        assert_eq!(arch_claim("bin/gunnar"), None);
        assert!(!lies(None, "aarch64"));
    }

    #[test]
    fn two_different_claims_in_one_path_are_no_claim() {
        // An ambiguous path must not be resolved by picking one.
        assert_eq!(arch_claim("build/x86_64-unknown-linux-gnu/aarch64/thing"), None);
    }

    #[test]
    fn the_same_claim_twice_is_still_that_claim() {
        assert_eq!(arch_claim("amd64/target/x86_64-unknown-linux-gnu/x"), Some("x86-64"));
    }

    #[test]
    fn a_claim_that_disagrees_with_the_header_is_a_lie() {
        assert!(lies(arch_claim("target/x86_64-unknown-linux-gnu/release/x"), "aarch64"));
        assert!(!lies(arch_claim("target/x86_64-unknown-linux-gnu/release/x"), "x86-64"));
    }

    #[test]
    fn aliases_fold_to_the_header_vocabulary() {
        assert_eq!(arch_claim("pkg/amd64/x"), Some("x86-64"));
        assert_eq!(arch_claim("pkg/arm64/x"), Some("aarch64"));
    }
}