bad64 0.12.0

Rust bindings for Binja's arm64 disassembler
Documentation
use std::fs;
use std::num::ParseIntError;

#[test]
fn testcases() {
    fn fuzzy_eq(expected: &str, actual: &str) -> bool {
        fn fuzzy_token(a: &str, b: &str) -> bool {
            fn parse_num(n: &str) -> Result<u64, ParseIntError> {
                let s = n
                    .trim_start_matches("#")
                    .trim_end_matches(",")
                    .trim_end_matches(".0")
                    .trim_end_matches("!")
                    .trim_end_matches("]");

                if s.starts_with("-") {
                    return match s {
                        _ if s.starts_with("-0x") => {
                            Ok(-i64::from_str_radix(s.trim_start_matches("-0x"), 16)? as u64)
                        }
                        _ => Ok(i64::from_str_radix(s, 10)? as u64),
                    };
                }

                return match s {
                    _ if s.starts_with("0x") => {
                        Ok(u64::from_str_radix(s.trim_start_matches("0x"), 16)?)
                    }
                    _ => Ok(u64::from_str_radix(s, 10)?),
                };
            }

            match (a, b) {
                ("cs", "hs") | ("hs", "cs") => true,
                ("lo", "cc") | ("cc", "lo") => true,
                _ if a.starts_with('#') || b.starts_with("#") => {
                    match (parse_num(a), parse_num(b)) {
                        (Ok(x), Ok(y)) => {
                            println!("parsed {:#x} {:#x}", x, y);
                            x == y || x & 0xffff_ffff == y & 0xffff_ffff || x & 0xff == y & 0xff
                        }
                        (Ok(_), Err(_)) => {
                            println!("couldnt parse: {}", b);
                            false
                        }
                        (Err(_), Ok(_)) => {
                            println!("couldnt parse: {}", a);
                            false
                        }
                        (Err(_), Err(_)) => {
                            println!("couldnt parse: {} / {}", a, b);
                            false
                        }
                    }
                }
                _ if a.to_lowercase() == b.to_lowercase() => true,
                _ => a == b,
            }
        }

        match actual {
            "axflag" if expected.starts_with("msr") => true,
            "xaflag" if expected.starts_with("msr") => true,
            "cfinv" if expected.starts_with("msr") => true,
            "dgh" if expected.starts_with("hint") => true,
            _ if actual.ends_with("sxtx]") && expected.ends_with("sxtx #0x0]") => true,
            _ if actual.ends_with("uxtw]") && expected.ends_with("uxtw #0x0]") => true,
            _ if actual.ends_with("sxtw]") && expected.ends_with("sxtw #0x0]") => true,
            _ if actual.starts_with("cmpp") && expected.starts_with("subps") => true,
            _ if actual.starts_with("mov") && expected.starts_with("dupm") => true,
            _ if actual.starts_with("msr pan") && expected.starts_with("msr s0_0") => true,
            _ if actual.starts_with("msr ssbs") && expected.starts_with("msr s0_3") => true,
            _ if actual.starts_with("sb") && expected.starts_with("msr s0_3") => true,
            _ if actual.starts_with("sdot") => true,
            _ if actual.starts_with("udot") => true,
            _ if actual == expected => true,
            _ if actual.to_lowercase() == expected.to_lowercase() => true,
            _ => expected
                .split(' ')
                .zip(actual.split(' '))
                .all(|(a, b)| fuzzy_token(a, b)),
        }
    }

    let testcases = fs::read_to_string("tests/test_cases.txt").unwrap();

    for (n, line) in testcases.lines().enumerate() {
        if line.starts_with("//") {
            println!("processing {}...", line);
            continue;
        }

        let chunks: Vec<&str> = line.trim_end().split_whitespace().collect();

        let op = u32::from_str_radix(chunks[0], 16).unwrap();
        let expected = chunks[1..].join(" ");

        let decoded = bad64::decode(op, 0x8000_0000_0000_0004);

        if decoded.is_err() && expected == "error" {
            continue;
        }

        let decoded = decoded.unwrap();

        let actual = format!("{}", decoded);

        if !fuzzy_eq(&expected, &actual) {
            println!("opcode:   {:x}", op);
            println!("expected: |{}|", expected);
            println!("actual:   |{}|", actual);
            println!("debug:    {:x?}", decoded);
            println!(
                "progress: {}/{}",
                n,
                testcases.lines().collect::<Vec<&str>>().len()
            );
            assert!(false);
        }
    }
}