<commit_before>#[macro_use]
extern crate lazy_static;
extern crate rustc_perf;
extern crate serde_json;
extern crate serde;

use std::fs::File;
use std::io::{Write, Read};
use std::path::Path;
use std::cmp::PartialEq;

use serde::{Deserialize, Serialize};

use rustc_perf::server::{self, GroupBy};
use rustc_perf::load::{Kind, InputData};
use rustc_perf::date::{OptionalDate, Date};
use rustc_perf::api::{data, tabular, days, stats};

lazy_static! {
    static ref INPUT_DATA: InputData = InputData::from_fs("tests/data").unwrap();
}

fn round_trip<T: Serialize + Deserialize>(value: &T) -> T {
    serde_json::from_str(&serde_json::to_string(value).unwrap()).unwrap()
}

fn from_file<P: AsRef<Path>, D: Deserialize>(path: P) -> D {
    let mut file = File::open(path).unwrap();
    let mut s = String::new();
    file.read_to_string(&mut s).unwrap();
    serde_json::from_str(&s).unwrap()
}

#[allow(dead_code)]
fn to_file<P: AsRef<Path>, S: Serialize>(path: P, value: S) {
    let mut file = File::create(path).unwrap();
    file.write_all(pretty_json(&value).as_bytes()).unwrap();
}

fn pretty_json<S: Serialize>(value: &S) -> String {
    serde_json::to_string_pretty(value).unwrap()
}

fn check_response<S>(received_value: S, expected_file: &str)
    where S: Serialize + Deserialize + PartialEq + ::std::fmt::Debug
{
    // Some types aren't equivalent after a round trip to their actual values.
    // This means we need to round trip through Serde to get saved representation on disk.
    let received_value = round_trip(&received_value);

    // Uncomment this line to refresh the expected results.
    // to_file(expected_file, &received_value);

    // The deserialized value from the file.
    let expected_value = from_file(expected_file);

    if received_value != expected_value {
        panic!("Compared {} body with server result, results not equal.", expected_file);
    }
}

#[test]
fn summary() {
    check_response(server::handle_summary(&INPUT_DATA), "tests/expected_results/summary.json");
}

#[test]
fn info() {
    check_response(server::handle_info(&INPUT_DATA), "tests/expected_results/info.json");
}

#[test]
fn data_crate_benchmarks() {
    check_response(server::handle_data(data::Request {
                                    start_date: OptionalDate::CouldNotParse("".into()),
                                    end_date: OptionalDate::CouldNotParse("".into()),
                                    group_by: GroupBy::Crate,
                                    kind: Kind::Benchmarks,
                                    phases: vec!["total".into()],
                                    crates: vec!["helloworld".into(), "regex.0.1.30".into()],
                                }, &INPUT_DATA),
                                "tests/expected_results/data_crate_benchmarks.json");
}

#[test]
fn data_crate_rustc_total() {
    check_response(server::handle_data(data::Request {
                                    start_date: OptionalDate::CouldNotParse("".into()),
                                    end_date: OptionalDate::CouldNotParse("".into()),
                                    group_by: GroupBy::Crate,
                                    kind: Kind::Rustc,
                                    phases: vec!["total".into()],
                                    crates: vec!["total".into()],
                                }, &INPUT_DATA),
                                "tests/expected_results/data_crate_rustc_total.json");
}

#[test]
fn tabular_rustc() {
    check_response(server::handle_tabular(tabular::Request {
                                    kind: Kind::Rustc,
                                    date: OptionalDate::CouldNotParse("".into()),
                                }, &INPUT_DATA), "tests/expected_results/tabular_rustc.json");
}

#[test]
fn tabular_benchmarks() {
    check_response(server::handle_tabular(tabular::Request {
                                    kind: Kind::Benchmarks,
                                    date: OptionalDate::CouldNotParse("".into()),
                                }, &INPUT_DATA), "tests/expected_results/tabular_benchmarks.json");
}

fn ymd_date(year: i32, month: u32, day: u32) -> OptionalDate {
    OptionalDate::Date(Date::ymd_hms(year, month, day, 0, 0, 0))
}

#[test]
fn days_benchmarks() {
    check_response(server::handle_days(days::Request {
                                    kind: Kind::Benchmarks,
                                    date_a: ymd_date(2016, 02, 21),
                                    date_b: ymd_date(2016, 03, 22),
                                    crates: vec!["helloworld".into(), "regex.0.1.30".into()],
                                    phases: vec!["total".into()],
                                    group_by: GroupBy::Crate,
                                }, &INPUT_DATA), "tests/expected_results/days_benchmarks.json");
}

#[test]
fn days_rustc() {
    check_response(server::handle_days(days::Request {
                                    kind: Kind::Rustc,
                                    date_a: ymd_date(2016, 02, 21),
                                    date_b: ymd_date(2016, 03, 22),
                                    crates: vec!["total".into()],
                                    phases: vec!["total".into()],
                                    group_by: GroupBy::Crate,
                                }, &INPUT_DATA), "tests/expected_results/days_rustc.json");
}

#[test]
fn stats_benchmarks() {
    check_response(server::handle_stats(stats::Request {
                                    kind: Kind::Benchmarks,
                                    start_date: OptionalDate::CouldNotParse("".into()),
                                    end_date: OptionalDate::CouldNotParse("".into()),
                                    crates: vec!["helloworld".into(), "regex.0.1.30".into()],
                                    phases: vec!["total".into()],
                                }, &INPUT_DATA), "tests/expected_results/stats_benchmarks.json");
}

#[test]
fn stats_rustc() {
    check_response(server::handle_stats(stats::Request {
                                    kind: Kind::Rustc,
                                    start_date: OptionalDate::CouldNotParse("".into()),
                                    end_date: OptionalDate::CouldNotParse("".into()),
                                    crates: vec!["total".into()],
                                    phases: vec!["total".into()],
                                }, &INPUT_DATA), "tests/expected_results/stats_rustc.json");
}
<commit_msg>Clean up styling in test code<commit_after>#[macro_use]
extern crate lazy_static;
extern crate rustc_perf;
extern crate serde_json;
extern crate serde;

use std::fs::File;
use std::io::{Write, Read};
use std::path::Path;
use std::cmp::PartialEq;

use serde::{Deserialize, Serialize};

use rustc_perf::server::{self, GroupBy};
use rustc_perf::load::{Kind, InputData};
use rustc_perf::date::{OptionalDate, Date};
use rustc_perf::api::{data, tabular, days, stats};

lazy_static! {
    static ref INPUT_DATA: InputData = InputData::from_fs("tests/data").unwrap();
}

fn round_trip<T: Serialize + Deserialize>(value: &T) -> T {
    serde_json::from_str(&serde_json::to_string(value).unwrap()).unwrap()
}

fn from_file<P: AsRef<Path>, D: Deserialize>(path: P) -> D {
    let mut file = File::open(path).unwrap();
    let mut s = String::new();
    file.read_to_string(&mut s).unwrap();
    serde_json::from_str(&s).unwrap()
}

#[allow(dead_code)]
fn to_file<P: AsRef<Path>, S: Serialize>(path: P, value: S) {
    let mut file = File::create(path).unwrap();
    file.write_all(pretty_json(&value).as_bytes()).unwrap();
}

fn pretty_json<S: Serialize>(value: &S) -> String {
    serde_json::to_string_pretty(value).unwrap()
}

fn check_response<S>(received_value: S, expected_file: &str)
where
    S: Serialize + Deserialize + PartialEq + ::std::fmt::Debug,
{
    // Some types aren't equivalent after a round trip to their actual values.
    // This means we need to round trip through Serde to get saved representation on disk.
    let received_value = round_trip(&received_value);

    // Uncomment this line to refresh the expected results.
    // to_file(expected_file, &received_value);

    // The deserialized value from the file.
    let expected_value = from_file(expected_file);

    if received_value != expected_value {
        panic!(
            "Compared {} body with server result, results not equal.",
            expected_file
        );
    }
}

#[test]
fn summary() {
    check_response(
        server::handle_summary(&INPUT_DATA),
        "tests/expected_results/summary.json",
    );
}

#[test]
fn info() {
    check_response(
        server::handle_info(&INPUT_DATA),
        "tests/expected_results/info.json",
    );
}

#[test]
fn data_crate_benchmarks() {
    check_response(
        server::handle_data(
            data::Request {
                start_date: OptionalDate::CouldNotParse("".into()),
                end_date: OptionalDate::CouldNotParse("".into()),
                group_by: GroupBy::Crate,
                kind: Kind::Benchmarks,
                phases: vec!["total".into()],
                crates: vec!["helloworld".into(), "regex.0.1.30".into()],
            },
            &INPUT_DATA,
        ),
        "tests/expected_results/data_crate_benchmarks.json",
    );
}

#[test]
fn data_crate_rustc_total() {
    check_response(
        server::handle_data(
            data::Request {
                start_date: OptionalDate::CouldNotParse("".into()),
                end_date: OptionalDate::CouldNotParse("".into()),
                group_by: GroupBy::Crate,
                kind: Kind::Rustc,
                phases: vec!["total".into()],
                crates: vec!["total".into()],
            },
            &INPUT_DATA,
        ),
        "tests/expected_results/data_crate_rustc_total.json",
    );
}

#[test]
fn tabular_rustc() {
    check_response(
        server::handle_tabular(
            tabular::Request {
                kind: Kind::Rustc,
                date: OptionalDate::CouldNotParse("".into()),
            },
            &INPUT_DATA,
        ),
        "tests/expected_results/tabular_rustc.json",
    );
}

#[test]
fn tabular_benchmarks() {
    check_response(
        server::handle_tabular(
            tabular::Request {
                kind: Kind::Benchmarks,
                date: OptionalDate::CouldNotParse("".into()),
            },
            &INPUT_DATA,
        ),
        "tests/expected_results/tabular_benchmarks.json",
    );
}

fn ymd_date(year: i32, month: u32, day: u32) -> OptionalDate {
    OptionalDate::Date(Date::ymd_hms(year, month, day, 0, 0, 0))
}

#[test]
fn days_benchmarks() {
    check_response(
        server::handle_days(
            days::Request {
                kind: Kind::Benchmarks,
                date_a: ymd_date(2016, 02, 21),
                date_b: ymd_date(2016, 03, 22),
                crates: vec!["helloworld".into(), "regex.0.1.30".into()],
                phases: vec!["total".into()],
                group_by: GroupBy::Crate,
            },
            &INPUT_DATA,
        ),
        "tests/expected_results/days_benchmarks.json",
    );
}

#[test]
fn days_rustc() {
    check_response(
        server::handle_days(
            days::Request {
                kind: Kind::Rustc,
                date_a: ymd_date(2016, 02, 21),
                date_b: ymd_date(2016, 03, 22),
                crates: vec!["total".into()],
                phases: vec!["total".into()],
                group_by: GroupBy::Crate,
            },
            &INPUT_DATA,
        ),
        "tests/expected_results/days_rustc.json",
    );
}

#[test]
fn stats_benchmarks() {
    check_response(
        server::handle_stats(
            stats::Request {
                kind: Kind::Benchmarks,
                start_date: OptionalDate::CouldNotParse("".into()),
                end_date: OptionalDate::CouldNotParse("".into()),
                crates: vec!["helloworld".into(), "regex.0.1.30".into()],
                phases: vec!["total".into()],
            },
            &INPUT_DATA,
        ),
        "tests/expected_results/stats_benchmarks.json",
    );
}

#[test]
fn stats_rustc() {
    check_response(
        server::handle_stats(
            stats::Request {
                kind: Kind::Rustc,
                start_date: OptionalDate::CouldNotParse("".into()),
                end_date: OptionalDate::CouldNotParse("".into()),
                crates: vec!["total".into()],
                phases: vec!["total".into()],
            },
            &INPUT_DATA,
        ),
        "tests/expected_results/stats_rustc.json",
    );
}
<|endoftext|>


<commit_before>extern crate trustines;

mod memory {
    use trustines::memory::Memory;
    #[test]
    fn write() {
        let mut m = Memory::new();
        m.write(0, &[0,1,2]);
        assert_eq!(0,m.read8(0).unwrap());
        assert_eq!(1,m.read8(1).unwrap());
        assert_eq!(2,m.read8(2).unwrap());
        m.write(1, &[3]);
        assert_eq!(0,m.read8(0).unwrap());
        assert_eq!(3,m.read8(1).unwrap());
        assert_eq!(2,m.read8(2).unwrap());
    }

    #[test]
    fn read8_basic() {
        let mut m = Memory::new();
        m.write(0,&[5,10]);
        assert_eq!(5,m.read8(0).unwrap());
        assert_eq!(10,m.read8(1).unwrap());
    }
    #[test]
    fn write8_basic() {
        let mut m = Memory::new();
        m.write8(0,5);
        assert_eq!(5,m.mem[0]);

        m.write8(1,10);
        assert_eq!(5,m.mem[0]);
        assert_eq!(10,m.mem[1]);
    }

    #[test]
    fn read16_basic() {
        let mut m = Memory::new();
        m.write(0,&[2,1,0]);
        assert_eq!(258,m.read16(0).unwrap());
        assert_eq!(1,m.read16(1).unwrap());
    }
    #[test]
    fn write16_basic() {
        let mut m = Memory::new();
        m.write16(0,258);
        assert_eq!(2,m.mem[0]);
        assert_eq!(1,m.mem[1]);
    }
    #[test]
    fn readwrite8() {
        let mut m = Memory::new();
        m.write8(0,5);
        m.write8(1,10);
        assert_eq!(5,m.read8(0).unwrap());
        assert_eq!(10,m.read8(1).unwrap());
    }
    #[test]
    fn readwrite16() {
        let mut m = Memory::new();
        m.write16(0,258);
        m.write16(2,300);
        assert_eq!(258,m.read16(0).unwrap());
        assert_eq!(300,m.read16(2).unwrap());
    }
}

mod address_mode {
    use trustines::cpu;
    use trustines::memory::Memory;
    use trustines::cpu::OpcodeClass;
    use trustines::cpu::AddressMode;

    fn build_executor() -> cpu::CpuExecutor {
        let opcode_info = cpu::opcode::load_from_file("resources/opcodes.csv").unwrap();
        return cpu::CpuExecutor::new(opcode_info.0);
    }
    fn build_memory(instr:u8,index:u16, ops: &[u8]) -> Memory {
        let mut m = Memory::new();
        update_memory(&mut m,instr,index,ops);
        return m;
    }
    fn update_memory(m:&mut Memory, instr:u8,index:u16, ops: &[u8]) {
        m.write8(index,instr);
        if ops.len() > 0 {
            m.write(index+1,ops);
        }
    }

    // NOTE: the opcodes specified in build_memory are not being executed, so the
    //       opcode class (ADC, ASL, BRK, etc) don't actually matter.  What matters
    //       is the addressing mode (Absolute, AbsoluteX, ZeroPage, etc)
    //

// ------------------ Non-Indexed, Non-Memory ------------------ //

    #[test]
    fn accumulator() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = Memory::new();
        let exec = build_executor();

        mem.write8(0,0x0A); // 0x0A = ASL Accumulator

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0x0A);

        match cpu.decode_register.info.opcode_class {
            OpcodeClass::ASL => {},
            _ => panic!("Expected ASL opcode class")
        }
        match cpu.decode_register.info.address_mode {
            AddressMode::Accumulator => {},
            _ => panic!("Expected Accumulator address mode")
        }
    }
    #[test]
    fn immediate() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = Memory::new();
        let exec = build_executor();

        mem.write8(0,0x69); // 0x69 = ADC Immediate

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0x69);

        match cpu.decode_register.info.opcode_class {
            OpcodeClass::ADC => {},
            _ => panic!("Expected ADC opcode class")
        }
        match cpu.decode_register.info.address_mode {
            AddressMode::Immediate => {},
            _ => panic!("Expected Immediate address mode")
        }
    }
    #[test]
    fn implied() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = Memory::new();
        let exec = build_executor();

        mem.write8(0,0x00); // 0x00 = BRK Implied

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0x00);

        match cpu.decode_register.info.opcode_class {
            OpcodeClass::BRK => {},
            _ => panic!("Expected BRK opcode class")
        }
        match cpu.decode_register.info.address_mode {
            AddressMode::Implied => {},
            _ => panic!("Expected Implied address mode")
        }
    }

// ------------------ Non-Indexed, Memory ------------------ //

    #[test]
    fn absolute() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = Memory::new();
        let exec = build_executor();

        mem.write8(0,0x6D); //0x6D = ADC Absolute
        mem.write16(1,300);
        mem.write8(300,5);

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);
        let s = OpcodeClass::ADC;

        assert_eq!(0x6D,cpu.instruction_register);

        match cpu.decode_register.info.opcode_class {
            OpcodeClass::ADC => {},
            _ => panic!("Expected ADC opcode class")
        }
        match cpu.decode_register.info.address_mode {
            AddressMode::Absolute => {},
            _ => panic!("Expected Absolute address mode")
        }

        assert_eq!(300,cpu.decode_register.addr_final.unwrap());
        assert_eq!(5,cpu.decode_register.value_final.unwrap());
    }
    #[test]
    fn indirect() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = Memory::new();
        let exec = build_executor();

        mem.write8(0,0x6C); // 0x6C = JMP Indirect
        mem.write16(1,300);
        mem.write16(300,500);

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0x6C);

        match cpu.decode_register.info.opcode_class {
            OpcodeClass::JMP => {},
            _ => panic!("Expected JMP opcode class")
        }
        match cpu.decode_register.info.address_mode {
            AddressMode::Indirect => {},
            _ => panic!("Expected Indirect address mode")
        }

        assert_eq!(300,cpu.decode_register.addr_intermediate.unwrap());
        assert_eq!(500,cpu.decode_register.addr_final.unwrap());
    }
    #[test]
    fn relative() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = Memory::new();
        let exec = build_executor();

        mem.write8(0,0x90); // 0x90 = BCC IndirectIndexed
        mem.write8(1,100);

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0x90);

        match cpu.decode_register.info.opcode_class {
            OpcodeClass::BCC => {},
            _ => panic!("Expected BCC opcode class")
        }
        match cpu.decode_register.info.address_mode {
            AddressMode::Relative => {},
            _ => panic!("Expected Relative address mode")
        }
        assert_eq!(1,cpu.decode_register.addr_final.unwrap());
        assert_eq!(100,cpu.decode_register.value_final.unwrap());
    }
    #[test]
    fn zeropage() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = Memory::new();
        let exec = build_executor();

        mem.write8(0,0x65); // 0x65 = ADC IndirectIndexed
        mem.write8(1,100);
        mem.write8(100,5);

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0x65);
        match cpu.decode_register.info.opcode_class {
            OpcodeClass::ADC => {},
            _ => panic!("Expected ADC opcode class")
        }
        match cpu.decode_register.info.address_mode {
            AddressMode::ZeroPage => {},
            _ => panic!("Expected ZeroPage address mode")
        }
        assert_eq!(100,cpu.decode_register.addr_final.unwrap());
        assert_eq!(5,cpu.decode_register.value_final.unwrap());
    }

// ------------------ Indexed, Memory ------------------ //

    #[test]
    fn absolute_x() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = build_memory(0x7D,0, &[]); // 0x7D = ADC AbsoluteX
        let exec = build_executor();

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0x7D);
    }
    #[test]
    fn absolute_y() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = build_memory(0x79,0, &[]);// 0x79 = ADC AbsoluteY
        let exec = build_executor();

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0x79);
    }
    #[test]
    fn zeropage_x() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = build_memory(0x75,0, &[]);// 0x75 = LDX ZeroPageX
        let exec = build_executor();

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0x75);
    }
    #[test]
    fn zeropage_y() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = build_memory(0xB6,0, &[]);// 0xB6 = LDX IndirectIndexed
        let exec = build_executor();

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0xB6);
    }
    #[test]
    fn indexed_indirect() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = build_memory(0x61,0, &[]);// 0x61 = ADC IndexedIndirect
        let exec = build_executor();

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0x61);
    }
    #[test]
    fn indirect_indexed() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = build_memory(0x71,0, &[]);// 0x71 = ADC IndirectIndexed
        let exec = build_executor();

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0x71);
    }
}

<commit_msg>finished adding the AddressMode and OpcodeClass tests<commit_after>extern crate trustines;

mod memory {
    use trustines::memory::Memory;
    #[test]
    fn write() {
        let mut m = Memory::new();
        m.write(0, &[0,1,2]);
        assert_eq!(0,m.read8(0).unwrap());
        assert_eq!(1,m.read8(1).unwrap());
        assert_eq!(2,m.read8(2).unwrap());
        m.write(1, &[3]);
        assert_eq!(0,m.read8(0).unwrap());
        assert_eq!(3,m.read8(1).unwrap());
        assert_eq!(2,m.read8(2).unwrap());
    }

    #[test]
    fn read8_basic() {
        let mut m = Memory::new();
        m.write(0,&[5,10]);
        assert_eq!(5,m.read8(0).unwrap());
        assert_eq!(10,m.read8(1).unwrap());
    }
    #[test]
    fn write8_basic() {
        let mut m = Memory::new();
        m.write8(0,5);
        assert_eq!(5,m.mem[0]);

        m.write8(1,10);
        assert_eq!(5,m.mem[0]);
        assert_eq!(10,m.mem[1]);
    }

    #[test]
    fn read16_basic() {
        let mut m = Memory::new();
        m.write(0,&[2,1,0]);
        assert_eq!(258,m.read16(0).unwrap());
        assert_eq!(1,m.read16(1).unwrap());
    }
    #[test]
    fn write16_basic() {
        let mut m = Memory::new();
        m.write16(0,258);
        assert_eq!(2,m.mem[0]);
        assert_eq!(1,m.mem[1]);
    }
    #[test]
    fn readwrite8() {
        let mut m = Memory::new();
        m.write8(0,5);
        m.write8(1,10);
        assert_eq!(5,m.read8(0).unwrap());
        assert_eq!(10,m.read8(1).unwrap());
    }
    #[test]
    fn readwrite16() {
        let mut m = Memory::new();
        m.write16(0,258);
        m.write16(2,300);
        assert_eq!(258,m.read16(0).unwrap());
        assert_eq!(300,m.read16(2).unwrap());
    }
}

mod address_mode {
    use trustines::cpu;
    use trustines::memory::Memory;
    use trustines::cpu::OpcodeClass;
    use trustines::cpu::AddressMode;

    fn build_executor() -> cpu::CpuExecutor {
        let opcode_info = cpu::opcode::load_from_file("resources/opcodes.csv").unwrap();
        return cpu::CpuExecutor::new(opcode_info.0);
    }

    // NOTE: the opcodes specified in build_memory are not being executed, so the
    //       opcode class (ADC, ASL, BRK, etc) don't actually matter.  What matters
    //       is the addressing mode (Absolute, AbsoluteX, ZeroPage, etc)
    //

// ------------------ Non-Indexed, Non-Memory ------------------ //

    #[test]
    fn accumulator() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = Memory::new();
        let exec = build_executor();

        mem.write8(0,0x0A); // 0x0A = ASL Accumulator

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0x0A);

        match cpu.decode_register.info.opcode_class {
            OpcodeClass::ASL => {},
            _ => panic!("Expected ASL opcode class")
        }
        match cpu.decode_register.info.address_mode {
            AddressMode::Accumulator => {},
            _ => panic!("Expected Accumulator address mode")
        }
    }
    #[test]
    fn immediate() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = Memory::new();
        let exec = build_executor();

        mem.write8(0,0x69); // 0x69 = ADC Immediate

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0x69);

        match cpu.decode_register.info.opcode_class {
            OpcodeClass::ADC => {},
            _ => panic!("Expected ADC opcode class")
        }
        match cpu.decode_register.info.address_mode {
            AddressMode::Immediate => {},
            _ => panic!("Expected Immediate address mode")
        }
    }
    #[test]
    fn implied() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = Memory::new();
        let exec = build_executor();

        mem.write8(0,0x00); // 0x00 = BRK Implied

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0x00);

        match cpu.decode_register.info.opcode_class {
            OpcodeClass::BRK => {},
            _ => panic!("Expected BRK opcode class")
        }
        match cpu.decode_register.info.address_mode {
            AddressMode::Implied => {},
            _ => panic!("Expected Implied address mode")
        }
    }

// ------------------ Non-Indexed, Memory ------------------ //

    #[test]
    fn absolute() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = Memory::new();
        let exec = build_executor();

        mem.write8(0,0x6D); //0x6D = ADC Absolute
        mem.write16(1,300);
        mem.write8(300,5);

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);
        let s = OpcodeClass::ADC;

        assert_eq!(0x6D,cpu.instruction_register);

        match cpu.decode_register.info.opcode_class {
            OpcodeClass::ADC => {},
            _ => panic!("Expected ADC opcode class")
        }
        match cpu.decode_register.info.address_mode {
            AddressMode::Absolute => {},
            _ => panic!("Expected Absolute address mode")
        }

        assert_eq!(300,cpu.decode_register.addr_final.unwrap());
        assert_eq!(5,cpu.decode_register.value_final.unwrap());
    }
    #[test]
    fn indirect() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = Memory::new();
        let exec = build_executor();

        mem.write8(0,0x6C); // 0x6C = JMP Indirect
        mem.write16(1,300);
        mem.write16(300,500);

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0x6C);

        match cpu.decode_register.info.opcode_class {
            OpcodeClass::JMP => {},
            _ => panic!("Expected JMP opcode class")
        }
        match cpu.decode_register.info.address_mode {
            AddressMode::Indirect => {},
            _ => panic!("Expected Indirect address mode")
        }

        assert_eq!(300,cpu.decode_register.addr_intermediate.unwrap());
        assert_eq!(500,cpu.decode_register.addr_final.unwrap());
    }
    #[test]
    fn relative() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = Memory::new();
        let exec = build_executor();

        mem.write8(0,0x90); // 0x90 = BCC IndirectIndexed
        mem.write8(1,100);

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0x90);

        match cpu.decode_register.info.opcode_class {
            OpcodeClass::BCC => {},
            _ => panic!("Expected BCC opcode class")
        }
        match cpu.decode_register.info.address_mode {
            AddressMode::Relative => {},
            _ => panic!("Expected Relative address mode")
        }
        assert_eq!(1,cpu.decode_register.addr_final.unwrap());
        assert_eq!(100,cpu.decode_register.value_final.unwrap());
    }
    #[test]
    fn zeropage() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = Memory::new();
        let exec = build_executor();

        mem.write8(0,0x65); // 0x65 = ADC IndirectIndexed
        mem.write8(1,100);
        mem.write8(100,5);

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0x65);

        match cpu.decode_register.info.opcode_class {
            OpcodeClass::ADC => {},
            _ => panic!("Expected ADC opcode class")
        }
        match cpu.decode_register.info.address_mode {
            AddressMode::ZeroPage => {},
            _ => panic!("Expected ZeroPage address mode")
        }
        assert_eq!(100,cpu.decode_register.addr_final.unwrap());
        assert_eq!(5,cpu.decode_register.value_final.unwrap());
    }

// ------------------ Indexed, Memory ------------------ //

    #[test]
    fn absolute_x() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = Memory::new();
        let exec = build_executor();

        mem.write8(0,0x7D); // 0x7D = ADC AbsoluteX

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0x7D);

        match cpu.decode_register.info.opcode_class {
            OpcodeClass::ADC => {},
            _ => panic!("Expected ADC opcode class")
        }
        match cpu.decode_register.info.address_mode {
            AddressMode::AbsoluteX => {},
            _ => panic!("Expected AbsoluteX address mode")
        }
    }
    #[test]
    fn absolute_y() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = Memory::new();
        let exec = build_executor();

        mem.write8(0,0x79); // 0x79 = ADC AbsoluteY

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0x79);

        match cpu.decode_register.info.opcode_class {
            OpcodeClass::ADC => {},
            _ => panic!("Expected ADC opcode class")
        }
        match cpu.decode_register.info.address_mode {
            AddressMode::AbsoluteY => {},
            _ => panic!("Expected Absolutey address mode")
        }
    }
    #[test]
    fn zeropage_x() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = Memory::new();
        let exec = build_executor();

        mem.write8(0,0x75); // 0x75 = ADC ZeroPageX

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0x75);

        match cpu.decode_register.info.opcode_class {
            OpcodeClass::ADC => {},
            _ => panic!("Expected ADC opcode class")
        }
        match cpu.decode_register.info.address_mode {
            AddressMode::ZeroPageX => {},
            _ => panic!("Expected ZeroPageX address mode")
        }
    }
    #[test]
    fn zeropage_y() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = Memory::new();
        let exec = build_executor();

        mem.write8(0,0xB6); // 0xB6 = LDX IndirectIndexed

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0xB6);

        match cpu.decode_register.info.opcode_class {
            OpcodeClass::LDX => {},
            _ => panic!("Expected LDX opcode class")
        }
        match cpu.decode_register.info.address_mode {
            AddressMode::ZeroPageY => {},
            _ => panic!("Expected ZeroPageY address mode")
        }
    }
    #[test]
    fn indexed_indirect() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = Memory::new();
        let exec = build_executor();

        mem.write8(0,0x61); // 0x61 = ADC IndexedIndirect

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0x61);

        match cpu.decode_register.info.opcode_class {
            OpcodeClass::ADC => {},
            _ => panic!("Expected ADC opcode class")
        }
        match cpu.decode_register.info.address_mode {
            AddressMode::IndexedIndirect => {},
            _ => panic!("Expected IndexedIndirect address mode")
        }
    }
    #[test]
    fn indirect_indexed() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = Memory::new();
        let exec = build_executor();

        mem.write8(0,0x71); // 0x71 = ADC IndirectIndexed

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0x71);

        match cpu.decode_register.info.opcode_class {
            OpcodeClass::ADC => {},
            _ => panic!("Expected ADC opcode class")
        }
        match cpu.decode_register.info.address_mode {
            AddressMode::IndirectIndexed => {},
            _ => panic!("Expected IndirectIndexed address mode")
        }
    }
}

<|endoftext|>


<commit_before>#[macro_use]
extern crate simple_bitfield;

simple_bitfield! {
    #[derive(Copy, Clone)]
    /// documentation comments also work!
    struct FooBar(u32); // newtype name, underlying type
    // getter name, setter name: msb (included), lsb
    foo1, set_foo1: 0, 0;
    u8;
    foo2, set_foo2: 31, 31;
    foo3, set_foo3: 3, 0;
    u16, foo4, set_foo4: 31, 28;
    // getter name, setter name: msb of first element (included), lsb of first element; count
    foo5, set_foo5: 0, 0, 32;
    u32;
    foo6, set_foo6: 5, 3, 3;
    getter_only, _: 3, 1;
    _, setter_only: 4, 2;
    getter_only_array, _: 5, 3, 3;
    _, setter_only_array: 6, 4, 3;
    all_bits, set_all_bits: 31, 0;
}

#[test]
fn test_single_bit() {
    let mut fb = FooBar(0);

    fb.set_foo1(1);
    assert_eq!(0x1, fb.0);
    assert_eq!(0x1, fb.foo1());
    assert_eq!(0x0, fb.foo2());

    fb.set_foo2(1);
    assert_eq!(0x80000001, fb.0);
    assert_eq!(0x1, fb.foo1());
    assert_eq!(0x1, fb.foo2());

    fb.set_foo1(0);
    assert_eq!(0x80000000, fb.0);
    assert_eq!(0x0, fb.foo1());
    assert_eq!(0x1, fb.foo2());
}

#[test]
fn test_single_bit_plus_garbage() {
    let mut fb = FooBar(0);

    fb.set_foo1(0b10);
    assert_eq!(0x0, fb.0);
    assert_eq!(0x0, fb.foo1());
    assert_eq!(0x0, fb.foo2());

    fb.set_foo1(0b11);
    assert_eq!(0x1, fb.0);
    assert_eq!(0x1, fb.foo1());
    assert_eq!(0x0, fb.foo2());

}

#[test]
fn test_multiple_bit() {
    let mut fb = FooBar(0);

    fb.set_foo3(0x0F);
    assert_eq!(0xF, fb.0);
    assert_eq!(0xF, fb.foo3());
    assert_eq!(0x0, fb.foo4());

    fb.set_foo4(0x0F);
    assert_eq!(0xF000000F, fb.0);
    assert_eq!(0xF, fb.foo3());
    assert_eq!(0xF, fb.foo4());

    fb.set_foo3(0);
    assert_eq!(0xF0000000, fb.0);
    assert_eq!(0x0, fb.foo3());
    assert_eq!(0xF, fb.foo4());

    fb.set_foo3(0xA);
    assert_eq!(0xF000000A, fb.0);
    assert_eq!(0xA, fb.foo3());
    assert_eq!(0xF, fb.foo4());
}

#[test]
fn test_getter_setter_only() {
    let mut fb = FooBar(0);
    fb.setter_only(0x7);
    assert_eq!(0x1C, fb.0);
    assert_eq!(0x6, fb.getter_only());
}

#[test]
fn test_array_field1() {
    let mut fb = FooBar(0);

    fb.set_foo5(0, 1);
    assert_eq!(0x1, fb.0);
    assert_eq!(1, fb.foo5(0));

    fb.set_foo5(0, 0);
    assert_eq!(0x0, fb.0);
    assert_eq!(0, fb.foo5(0));

    fb.set_foo5(0, 1);
    fb.set_foo5(6, 1);
    fb.set_foo5(31, 1);
    assert_eq!(0x80000041, fb.0);
    assert_eq!(1, fb.foo5(0));
    assert_eq!(1, fb.foo5(6));
    assert_eq!(1, fb.foo5(31));
    assert_eq!(0, fb.foo5(1));
    assert_eq!(0, fb.foo5(5));
    assert_eq!(0, fb.foo5(7));
    assert_eq!(0, fb.foo5(30));
}

#[test]
fn test_array_field2() {
    let mut fb = FooBar(0);

    fb.set_foo6(0, 1);
    assert_eq!(0x8, fb.0);
    assert_eq!(1, fb.foo6(0));
    assert_eq!(0, fb.foo6(1));
    assert_eq!(0, fb.foo6(2));

    fb.set_foo6(0, 7);
    assert_eq!(0x38, fb.0);
    assert_eq!(7, fb.foo6(0));
    assert_eq!(0, fb.foo6(1));
    assert_eq!(0, fb.foo6(2));

    fb.set_foo6(2, 7);
    assert_eq!(0xE38, fb.0);
    assert_eq!(7, fb.foo6(0));
    assert_eq!(0, fb.foo6(1));
    assert_eq!(7, fb.foo6(2));

    fb.set_foo6(0, 0);
    assert_eq!(0xE00, fb.0);
    assert_eq!(0, fb.foo6(0));
    assert_eq!(0, fb.foo6(1));
    assert_eq!(7, fb.foo6(2));
}

#[test]
fn test_field_type() {
    let fb = FooBar(0);
    let _: u32 = fb.foo1();
    let _: u8 = fb.foo2();
    let _: u8 = fb.foo3();
    let _: u16 = fb.foo4();
    let _: u8 = fb.foo5(0);
    let _: u32 = fb.foo6(0);
}

#[test]
fn test_all_bits() {
    let mut fb = FooBar(0);

    assert_eq!(0, fb.all_bits());

    fb.set_all_bits(!0u32);
    assert_eq!(!0u32, fb.0);
    assert_eq!(!0u32, fb.all_bits());

    fb.0 = 0x80000001;
    assert_eq!(0x80000001, fb.all_bits());
}

#[test]
fn test_is_copy() {
    let a = FooBar(0);
    let _b = a;
    let _c = a;
}

simple_bitfield! {
    struct ArrayBitfield([u8]);
    foo1, set_foo1: 0, 0;
    foo2, set_foo2: 7, 0;
    foo3, set_foo3: 8, 1;
    foo4, set_foo4: 20, 4;
}

#[test]
fn test_arraybitfield() {
    let mut ab = ArrayBitfield([0; 3]);

    assert_eq!(0, ab.foo1());
    assert_eq!(0, ab.foo2());
    assert_eq!(0, ab.foo3());
    assert_eq!(0, ab.foo4());

    ab.set_foo1(1);
    assert_eq!([1, 0, 0], ab.0);
    assert_eq!(1, ab.foo1());
    assert_eq!(1, ab.foo2());
    assert_eq!(0, ab.foo3());
    assert_eq!(0, ab.foo4());

    ab.set_foo1(0);
    ab.set_foo2(0xFF);
    assert_eq!([0xFF, 0, 0], ab.0);
    assert_eq!(1, ab.foo1());
    assert_eq!(0xFF, ab.foo2());
    assert_eq!(0x7F, ab.foo3());
    assert_eq!(0x0F, ab.foo4());

    ab.set_foo2(0);
    ab.set_foo3(0xFF);
    assert_eq!([0xFE, 0x1, 0], ab.0);
    assert_eq!(0, ab.foo1());
    assert_eq!(0xFE, ab.foo2());
    assert_eq!(0xFF, ab.foo3());
    assert_eq!(0x1F, ab.foo4());

    ab.set_foo3(0);
    ab.set_foo4(0xFFFF);
    assert_eq!([0xF0, 0xFF, 0x0F], ab.0);
    assert_eq!(0, ab.foo1());
    assert_eq!(0xF0, ab.foo2());
    assert_eq!(0xF8, ab.foo3());
    assert_eq!(0xFFFF, ab.foo4());
}

simple_bitfield! {
    struct ArrayBitfield2([u16]);
    foo1, set_foo1: 0, 0;
    foo2, set_foo2: 7, 0;
    foo3, set_foo3: 8, 1;
    foo4, set_foo4: 20, 4;
}

#[test]
fn test_arraybitfield2() {
    let mut ab = ArrayBitfield2([0; 2]);

    assert_eq!(0, ab.foo1());
    assert_eq!(0, ab.foo2());
    assert_eq!(0, ab.foo3());
    assert_eq!(0, ab.foo4());

    ab.set_foo1(1);
    assert_eq!([1, 0], ab.0);
    assert_eq!(1, ab.foo1());
    assert_eq!(1, ab.foo2());
    assert_eq!(0, ab.foo3());
    assert_eq!(0, ab.foo4());

    ab.set_foo1(0);
    ab.set_foo2(0xFF);
    assert_eq!([0xFF, 0], ab.0);
    assert_eq!(1, ab.foo1());
    assert_eq!(0xFF, ab.foo2());
    assert_eq!(0x7F, ab.foo3());
    assert_eq!(0x0F, ab.foo4());

    ab.set_foo2(0);
    ab.set_foo3(0xFF);
    assert_eq!([0x1FE, 0x0], ab.0);
    assert_eq!(0, ab.foo1());
    assert_eq!(0xFE, ab.foo2());
    assert_eq!(0xFF, ab.foo3());
    assert_eq!(0x1F, ab.foo4());

    ab.set_foo3(0);
    ab.set_foo4(0xFFFF);
    assert_eq!([0xFFF0, 0xF], ab.0);
    assert_eq!(0, ab.foo1());
    assert_eq!(0xF0, ab.foo2());
    assert_eq!(0xF8, ab.foo3());
    assert_eq!(0xFFFF, ab.foo4());
}
<commit_msg>Add test for boolean field;<commit_after>#[macro_use]
extern crate simple_bitfield;

simple_bitfield! {
    #[derive(Copy, Clone)]
    /// documentation comments also work!
    struct FooBar(u32); // newtype name, underlying type
    // getter name, setter name: msb (included), lsb
    foo1, set_foo1: 0, 0;
    u8;
    foo2, set_foo2: 31, 31;
    foo3, set_foo3: 3, 0;
    u16, foo4, set_foo4: 31, 28;
    // getter name, setter name: msb of first element (included), lsb of first element; count
    foo5, set_foo5: 0, 0, 32;
    u32;
    foo6, set_foo6: 5, 3, 3;
    getter_only, _: 3, 1;
    _, setter_only: 4, 2;
    getter_only_array, _: 5, 3, 3;
    _, setter_only_array: 6, 4, 3;
    all_bits, set_all_bits: 31, 0;
    single_bit, set_single_bit: 3;
}

#[test]
fn test_single_bit() {
    let mut fb = FooBar(0);

    fb.set_foo1(1);
    assert_eq!(0x1, fb.0);
    assert_eq!(0x1, fb.foo1());
    assert_eq!(0x0, fb.foo2());
    assert_eq!(false, fb.single_bit());

    fb.set_foo2(1);
    assert_eq!(0x80000001, fb.0);
    assert_eq!(0x1, fb.foo1());
    assert_eq!(0x1, fb.foo2());
    assert_eq!(false, fb.single_bit());

    fb.set_foo1(0);
    assert_eq!(0x80000000, fb.0);
    assert_eq!(0x0, fb.foo1());
    assert_eq!(0x1, fb.foo2());
    assert_eq!(false, fb.single_bit());

    fb.set_single_bit(true);
    assert_eq!(0x80000008, fb.0);
    assert_eq!(0x0, fb.foo1());
    assert_eq!(0x1, fb.foo2());
    assert_eq!(true, fb.single_bit());
}

#[test]
fn test_single_bit_plus_garbage() {
    let mut fb = FooBar(0);

    fb.set_foo1(0b10);
    assert_eq!(0x0, fb.0);
    assert_eq!(0x0, fb.foo1());
    assert_eq!(0x0, fb.foo2());

    fb.set_foo1(0b11);
    assert_eq!(0x1, fb.0);
    assert_eq!(0x1, fb.foo1());
    assert_eq!(0x0, fb.foo2());

}

#[test]
fn test_multiple_bit() {
    let mut fb = FooBar(0);

    fb.set_foo3(0x0F);
    assert_eq!(0xF, fb.0);
    assert_eq!(0xF, fb.foo3());
    assert_eq!(0x0, fb.foo4());

    fb.set_foo4(0x0F);
    assert_eq!(0xF000000F, fb.0);
    assert_eq!(0xF, fb.foo3());
    assert_eq!(0xF, fb.foo4());

    fb.set_foo3(0);
    assert_eq!(0xF0000000, fb.0);
    assert_eq!(0x0, fb.foo3());
    assert_eq!(0xF, fb.foo4());

    fb.set_foo3(0xA);
    assert_eq!(0xF000000A, fb.0);
    assert_eq!(0xA, fb.foo3());
    assert_eq!(0xF, fb.foo4());
}

#[test]
fn test_getter_setter_only() {
    let mut fb = FooBar(0);
    fb.setter_only(0x7);
    assert_eq!(0x1C, fb.0);
    assert_eq!(0x6, fb.getter_only());
}

#[test]
fn test_array_field1() {
    let mut fb = FooBar(0);

    fb.set_foo5(0, 1);
    assert_eq!(0x1, fb.0);
    assert_eq!(1, fb.foo5(0));

    fb.set_foo5(0, 0);
    assert_eq!(0x0, fb.0);
    assert_eq!(0, fb.foo5(0));

    fb.set_foo5(0, 1);
    fb.set_foo5(6, 1);
    fb.set_foo5(31, 1);
    assert_eq!(0x80000041, fb.0);
    assert_eq!(1, fb.foo5(0));
    assert_eq!(1, fb.foo5(6));
    assert_eq!(1, fb.foo5(31));
    assert_eq!(0, fb.foo5(1));
    assert_eq!(0, fb.foo5(5));
    assert_eq!(0, fb.foo5(7));
    assert_eq!(0, fb.foo5(30));
}

#[test]
fn test_array_field2() {
    let mut fb = FooBar(0);

    fb.set_foo6(0, 1);
    assert_eq!(0x8, fb.0);
    assert_eq!(1, fb.foo6(0));
    assert_eq!(0, fb.foo6(1));
    assert_eq!(0, fb.foo6(2));

    fb.set_foo6(0, 7);
    assert_eq!(0x38, fb.0);
    assert_eq!(7, fb.foo6(0));
    assert_eq!(0, fb.foo6(1));
    assert_eq!(0, fb.foo6(2));

    fb.set_foo6(2, 7);
    assert_eq!(0xE38, fb.0);
    assert_eq!(7, fb.foo6(0));
    assert_eq!(0, fb.foo6(1));
    assert_eq!(7, fb.foo6(2));

    fb.set_foo6(0, 0);
    assert_eq!(0xE00, fb.0);
    assert_eq!(0, fb.foo6(0));
    assert_eq!(0, fb.foo6(1));
    assert_eq!(7, fb.foo6(2));
}

#[test]
fn test_field_type() {
    let fb = FooBar(0);
    let _: u32 = fb.foo1();
    let _: u8 = fb.foo2();
    let _: u8 = fb.foo3();
    let _: u16 = fb.foo4();
    let _: u8 = fb.foo5(0);
    let _: u32 = fb.foo6(0);
}

#[test]
fn test_all_bits() {
    let mut fb = FooBar(0);

    assert_eq!(0, fb.all_bits());

    fb.set_all_bits(!0u32);
    assert_eq!(!0u32, fb.0);
    assert_eq!(!0u32, fb.all_bits());

    fb.0 = 0x80000001;
    assert_eq!(0x80000001, fb.all_bits());
}

#[test]
fn test_is_copy() {
    let a = FooBar(0);
    let _b = a;
    let _c = a;
}

simple_bitfield! {
    struct ArrayBitfield([u8]);
    foo1, set_foo1: 0, 0;
    foo2, set_foo2: 7, 0;
    foo3, set_foo3: 8, 1;
    foo4, set_foo4: 20, 4;
}

#[test]
fn test_arraybitfield() {
    let mut ab = ArrayBitfield([0; 3]);

    assert_eq!(0, ab.foo1());
    assert_eq!(0, ab.foo2());
    assert_eq!(0, ab.foo3());
    assert_eq!(0, ab.foo4());

    ab.set_foo1(1);
    assert_eq!([1, 0, 0], ab.0);
    assert_eq!(1, ab.foo1());
    assert_eq!(1, ab.foo2());
    assert_eq!(0, ab.foo3());
    assert_eq!(0, ab.foo4());

    ab.set_foo1(0);
    ab.set_foo2(0xFF);
    assert_eq!([0xFF, 0, 0], ab.0);
    assert_eq!(1, ab.foo1());
    assert_eq!(0xFF, ab.foo2());
    assert_eq!(0x7F, ab.foo3());
    assert_eq!(0x0F, ab.foo4());

    ab.set_foo2(0);
    ab.set_foo3(0xFF);
    assert_eq!([0xFE, 0x1, 0], ab.0);
    assert_eq!(0, ab.foo1());
    assert_eq!(0xFE, ab.foo2());
    assert_eq!(0xFF, ab.foo3());
    assert_eq!(0x1F, ab.foo4());

    ab.set_foo3(0);
    ab.set_foo4(0xFFFF);
    assert_eq!([0xF0, 0xFF, 0x0F], ab.0);
    assert_eq!(0, ab.foo1());
    assert_eq!(0xF0, ab.foo2());
    assert_eq!(0xF8, ab.foo3());
    assert_eq!(0xFFFF, ab.foo4());
}

simple_bitfield! {
    struct ArrayBitfield2([u16]);
    foo1, set_foo1: 0, 0;
    foo2, set_foo2: 7, 0;
    foo3, set_foo3: 8, 1;
    foo4, set_foo4: 20, 4;
}

#[test]
fn test_arraybitfield2() {
    let mut ab = ArrayBitfield2([0; 2]);

    assert_eq!(0, ab.foo1());
    assert_eq!(0, ab.foo2());
    assert_eq!(0, ab.foo3());
    assert_eq!(0, ab.foo4());

    ab.set_foo1(1);
    assert_eq!([1, 0], ab.0);
    assert_eq!(1, ab.foo1());
    assert_eq!(1, ab.foo2());
    assert_eq!(0, ab.foo3());
    assert_eq!(0, ab.foo4());

    ab.set_foo1(0);
    ab.set_foo2(0xFF);
    assert_eq!([0xFF, 0], ab.0);
    assert_eq!(1, ab.foo1());
    assert_eq!(0xFF, ab.foo2());
    assert_eq!(0x7F, ab.foo3());
    assert_eq!(0x0F, ab.foo4());

    ab.set_foo2(0);
    ab.set_foo3(0xFF);
    assert_eq!([0x1FE, 0x0], ab.0);
    assert_eq!(0, ab.foo1());
    assert_eq!(0xFE, ab.foo2());
    assert_eq!(0xFF, ab.foo3());
    assert_eq!(0x1F, ab.foo4());

    ab.set_foo3(0);
    ab.set_foo4(0xFFFF);
    assert_eq!([0xFFF0, 0xF], ab.0);
    assert_eq!(0, ab.foo1());
    assert_eq!(0xF0, ab.foo2());
    assert_eq!(0xF8, ab.foo3());
    assert_eq!(0xFFFF, ab.foo4());
}
<|endoftext|>


<commit_before>extern crate snappy;

#[test]
/// Snappy: Create Compressor
fn should_create_compressor() {

	use std::io::{Write};
	use snappy::{Compressor, max_compressed_len};

	let mut sample: Vec<u8> = vec![];
	let n = Compressor::new(&mut sample).write(b"123456789").unwrap();

	// Assert Valid Written Size
	assert!(n == 9);
	// Result should be no more than max_compressed_len(src.len())
	assert!(sample.len() <= max_compressed_len(n));
}

<commit_msg>Fix Test<commit_after>extern crate snappy_rust;

#[test]
/// Snappy: Create Compressor
fn should_create_compressor() {

	use std::io::{Write};
	use snappy_rust::{Compressor, max_compressed_len};

	let mut sample: Vec<u8> = vec![];
	let n = Compressor::new(&mut sample).write(b"123456789").unwrap();

	// Assert Valid Written Size
	assert!(n == 9);
	// Result should be no more than max_compressed_len(src.len())
	assert!(sample.len() <= max_compressed_len(n));
}

<|endoftext|>


<commit_before>extern crate gbm;
extern crate syscall;

#[test]
fn integration_test() {
}

<commit_msg>whoops<commit_after>extern crate gbm;

#[test]
fn integration_test() {
}

<|endoftext|>


<commit_before>extern crate capstone_sys;
extern crate libc;

use libc::{c_char, size_t};
use capstone_sys::*;
use capstone_sys::x86::*;

const X86_CODE16: &'static [u8] = b"\x8d\x4c\x32\x08\x01\xd8\x81\xc6\x34\x12\x00\x00\x05\x23\x01\x00\x00\x36\x8b\x84\x91\x23\x01\x00\x00\x41\x8d\x84\x39\x89\x67\x00\x00\x8d\x87\x89\x67\x00\x00\xb4\xc6";
const X86_CODE32: &'static [u8] = b"\x8d\x4c\x32\x08\x01\xd8\x81\xc6\x34\x12\x00\x00\x05\x23\x01\x00\x00\x36\x8b\x84\x91\x23\x01\x00\x00\x41\x8d\x84\x39\x89\x67\x00\x00\x8d\x87\x89\x67\x00\x00\xb4\xc6";
const X86_CODE64: &'static [u8] = b"\x55\x48\x8b\x05\xb8\x13\x00\x00";

fn to_str(raw: &[c_char]) -> &str {
    unsafe {
        ::std::ffi::CStr::from_ptr(raw.as_ptr()).to_str().expect("invalid UTF-8")
    }
}

fn generic(arch: cs_arch, mode: cs_mode, code: &[u8], expected_size: size_t, expected_first: (&str, &str, &[x86_op_type])) {
    let mut handle: csh = 0;
    let err = unsafe { cs_open(arch, mode, &mut handle) };
    assert_eq!(err, CS_ERR_OK);

    // let err = unsafe { cs_option(handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT as size_t) };
    // assert_eq!(err, CS_ERR_OK);

    let err = unsafe { cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON as size_t) };
    assert_eq!(err, CS_ERR_OK);

    let mut instrs: *mut cs_insn = ::std::ptr::null_mut();
    let size = unsafe { cs_disasm(handle, code.as_ptr(), code.len(), 0, 0 /* read as much as possible */, &mut instrs) };
    assert_eq!(size, expected_size);
    assert!(!instrs.is_null());

    let instr = unsafe { &*instrs };
    let (mnemonic, op_str, ops) = expected_first;
    assert_eq!(to_str(&instr.mnemonic), mnemonic);
    assert_eq!(to_str(&instr.op_str), op_str);
    assert!(!instr.detail.is_null());
    let detail = unsafe { (&*instr.detail).x86() };
    assert_eq!(detail.op_count, ops.len() as u8);
    for i in 0..ops.len() {
        assert_eq!(detail.operands[i].typ, ops[i]);
    }

    unsafe {
        cs_close(&mut handle);
    }
}

#[test]
fn test_x86_16() {
    generic(CS_ARCH_X86, CS_MODE_16, X86_CODE16, 15, ("lea", "cx, word ptr [si + 0x32]", &[X86_OP_REG, X86_OP_MEM]));
}

#[test]
fn test_x86_32() {
    generic(CS_ARCH_X86, CS_MODE_32, X86_CODE32, 9, ("lea", "ecx, dword ptr [edx + esi + 8]", &[X86_OP_REG, X86_OP_MEM]));
}

#[test]
fn test_x86_64() {
    generic(CS_ARCH_X86, CS_MODE_64, X86_CODE64, 2, ("push", "rbp", &[X86_OP_REG]));
}
<commit_msg>Add cs_errno assert to x86 test<commit_after>extern crate capstone_sys;
extern crate libc;

use libc::{c_char, size_t};
use capstone_sys::*;
use capstone_sys::x86::*;

const X86_CODE16: &'static [u8] = b"\x8d\x4c\x32\x08\x01\xd8\x81\xc6\x34\x12\x00\x00\x05\x23\x01\x00\x00\x36\x8b\x84\x91\x23\x01\x00\x00\x41\x8d\x84\x39\x89\x67\x00\x00\x8d\x87\x89\x67\x00\x00\xb4\xc6";
const X86_CODE32: &'static [u8] = b"\x8d\x4c\x32\x08\x01\xd8\x81\xc6\x34\x12\x00\x00\x05\x23\x01\x00\x00\x36\x8b\x84\x91\x23\x01\x00\x00\x41\x8d\x84\x39\x89\x67\x00\x00\x8d\x87\x89\x67\x00\x00\xb4\xc6";
const X86_CODE64: &'static [u8] = b"\x55\x48\x8b\x05\xb8\x13\x00\x00";

fn to_str(raw: &[c_char]) -> &str {
    unsafe {
        ::std::ffi::CStr::from_ptr(raw.as_ptr()).to_str().expect("invalid UTF-8")
    }
}

fn generic(arch: cs_arch, mode: cs_mode, code: &[u8], expected_size: size_t, expected_first: (&str, &str, &[x86_op_type])) {
    let mut handle: csh = 0;
    let err = unsafe { cs_open(arch, mode, &mut handle) };
    assert_eq!(err, CS_ERR_OK);

    // let err = unsafe { cs_option(handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT as size_t) };
    // assert_eq!(err, CS_ERR_OK);

    let err = unsafe { cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON as size_t) };
    assert_eq!(err, CS_ERR_OK);

    let mut instrs: *mut cs_insn = ::std::ptr::null_mut();
    let size = unsafe { cs_disasm(handle, code.as_ptr(), code.len(), 0, 0 /* read as much as possible */, &mut instrs) };
    let err = unsafe { cs_errno(handle) };
    assert_eq!(err, CS_ERR_OK);
    assert_eq!(size, expected_size);
    assert!(!instrs.is_null());

    let instr = unsafe { &*instrs };
    let (mnemonic, op_str, ops) = expected_first;
    assert_eq!(to_str(&instr.mnemonic), mnemonic);
    assert_eq!(to_str(&instr.op_str), op_str);
    assert!(!instr.detail.is_null());
    let detail = unsafe { (&*instr.detail).x86() };
    assert_eq!(detail.op_count, ops.len() as u8);
    for i in 0..ops.len() {
        assert_eq!(detail.operands[i].typ, ops[i]);
    }

    unsafe {
        cs_close(&mut handle);
    }
}

#[test]
fn test_x86_16() {
    generic(CS_ARCH_X86, CS_MODE_16, X86_CODE16, 15, ("lea", "cx, word ptr [si + 0x32]", &[X86_OP_REG, X86_OP_MEM]));
}

#[test]
fn test_x86_32() {
    generic(CS_ARCH_X86, CS_MODE_32, X86_CODE32, 9, ("lea", "ecx, dword ptr [edx + esi + 8]", &[X86_OP_REG, X86_OP_MEM]));
}

#[test]
fn test_x86_64() {
    generic(CS_ARCH_X86, CS_MODE_64, X86_CODE64, 2, ("push", "rbp", &[X86_OP_REG]));
}
<|endoftext|>


<commit_before>#![allow(dead_code, unused_imports)]

extern crate fitsio_sys as sys;
extern crate libc;

use std::ptr;
use std::ffi;

mod stringutils;

/// Error type
#[derive(Debug, PartialEq, Eq)]
pub struct FitsError {
    status: i32,
    message: String,
}

pub type Result<T> = std::result::Result<T, FitsError>;

/// Hdu description type
///
/// Any way of describing a HDU - number or string which either
/// changes the hdu by absolute number, or by name.
pub trait DescribesHdu {
    fn change_hdu(&self, fptr: &FitsFile) -> Result<()>;
}

impl DescribesHdu for usize {
    fn change_hdu(&self, f: &FitsFile) -> Result<()> {
        let mut _hdu_type = 0;
        let mut status = 0;
        unsafe {
            sys::ffmahd(f.fptr, (*self + 1) as i32, &mut _hdu_type, &mut status);
        }
        match status {
            0 => Ok(()),
            _ => {
                Err(FitsError {
                    status: status,
                    message: stringutils::status_to_string(status).unwrap(),
                })
            }
        }
    }
}

impl<'a> DescribesHdu for &'a str {
    fn change_hdu(&self, f: &FitsFile) -> Result<()> {
        let mut _hdu_type = 0;
        let mut status = 0;
        let c_hdu_name = ffi::CString::new(*self).unwrap();

        unsafe {
            sys::ffmnhd(f.fptr,
                        sys::HduType::ANY_HDU as libc::c_int,
                        c_hdu_name.into_raw(),
                        0,
                        &mut status);
        }

        match status {
            0 => Ok(()),
            _ => {
                Err(FitsError {
                    status: status,
                    message: stringutils::status_to_string(status).unwrap(),
                })
            }
        }
    }
}

/// Trait applied to types which can be read from a FITS header
///
/// This is currently:
///
/// * i32
/// * i64
/// * f32
/// * f64
/// * String
pub trait ReadsKey {
    fn read_key(f: &FitsFile, name: &str) -> Result<Self> where Self: std::marker::Sized;
}

macro_rules! reads_key_impl {
    ($t:ty, $func:ident) => (
        impl ReadsKey for $t {
            fn read_key(f: &FitsFile, name: &str) -> Result<Self> {
                let c_name = ffi::CString::new(name).unwrap();
                let mut status = 0;
                let mut value: Self = Self::default();

                unsafe {
                    sys::$func(f.fptr,
                           c_name.into_raw(),
                           &mut value,
                           ptr::null_mut(),
                           &mut status);
                }

                match status {
                    0 => Ok(value),
                    s => {
                        Err(FitsError {
                            status: s,
                            message: stringutils::status_to_string(s).unwrap(),
                        })
                    }
                }
            }
        }
    )
}

reads_key_impl!(i32, ffgkyl);
reads_key_impl!(i64, ffgkyj);
reads_key_impl!(f32, ffgkye);
reads_key_impl!(f64, ffgkyd);

impl ReadsKey for String {
    fn read_key(f: &FitsFile, name: &str) -> Result<Self> {
        let c_name = ffi::CString::new(name).unwrap();
        let mut status = 0;
        let mut value: Vec<libc::c_char> = vec![0; sys::MAX_VALUE_LENGTH];

        unsafe {
            sys::ffgkys(f.fptr,
                        c_name.into_raw(),
                        value.as_mut_ptr(),
                        ptr::null_mut(),
                        &mut status);
        }

        match status {
            0 => {
                let value: Vec<u8> = value.iter()
                    .map(|&x| x as u8)
                    .filter(|&x| x != 0)
                    .collect();
                Ok(String::from_utf8(value).unwrap())
            }
            status => {
                Err(FitsError {
                    status: status,
                    message: stringutils::status_to_string(status).unwrap(),
                })
            }
        }

    }
}

#[derive(PartialEq, Eq, Debug)]
pub enum HduInfo {
    ImageInfo {
        dimensions: usize,
        shape: Vec<usize>,
    },
    TableInfo {
        column_names: Vec<String>,
        column_types: Vec<sys::DataType>,
        num_rows: usize,
    },
}

pub struct FitsFile {
    fptr: *mut sys::fitsfile,
    pub filename: String,
}

fn typechar_to_data_type<T: Into<String>>(typechar: T) -> sys::DataType {
    match typechar.into().as_str() {
        "X" => sys::DataType::TBIT,
        "B" => sys::DataType::TBYTE,
        "L" => sys::DataType::TLOGICAL,
        "A" => sys::DataType::TSTRING,
        "I" => sys::DataType::TSHORT,
        "J" => sys::DataType::TLONG,
        "E" => sys::DataType::TFLOAT,
        "D" => sys::DataType::TDOUBLE,
        "C" => sys::DataType::TCOMPLEX,
        "M" => sys::DataType::TDBLCOMPLEX,
        other => panic!("Unhandled case: {}", other),
    }
}

unsafe fn fetch_hdu_info(fptr: *mut sys::fitsfile) -> Result<HduInfo> {
    let mut status = 0;
    let mut hdu_type = 0;

    sys::ffghdt(fptr, &mut hdu_type, &mut status);
    let hdu_type =
        match hdu_type {
            0 => {
                let mut dimensions = 0;
                sys::ffgidm(fptr, &mut dimensions, &mut status);

                let mut shape = vec![0; dimensions as usize];
                sys::ffgisz(fptr, dimensions, shape.as_mut_ptr(), &mut status);

                HduInfo::ImageInfo {
                    dimensions: dimensions as usize,
                    shape: shape.iter().map(|v| *v as usize).collect(),
                }
            }
            1 | 2 => {
                let mut num_rows = 0;
                sys::ffgnrw(fptr, &mut num_rows, &mut status);

                let mut num_cols = 0;
                sys::ffgncl(fptr, &mut num_cols, &mut status);
                let mut column_names = Vec::with_capacity(num_cols as usize);
                let mut column_types = Vec::with_capacity(num_cols as usize);

                for i in 0..num_cols {
                    let mut name_buffer: Vec<libc::c_char> = vec![0; 71];
                    let mut type_buffer: Vec<libc::c_char> = vec![0; 71];
                    sys::ffgbcl(fptr,
                                (i + 1) as i32,
                                name_buffer.as_mut_ptr(),
                                ptr::null_mut(),
                                type_buffer.as_mut_ptr(),
                                ptr::null_mut(),
                                ptr::null_mut(),
                                ptr::null_mut(),
                                ptr::null_mut(),
                                ptr::null_mut(),
                                &mut status);
                    column_names.push(stringutils::buf_to_string(&name_buffer).unwrap());
                    column_types.push(typechar_to_data_type(stringutils::buf_to_string(&type_buffer)
                            .unwrap()));
                }

                HduInfo::TableInfo {
                    column_names: column_names,
                    column_types: column_types,
                    num_rows: num_rows as usize,
                }
            }
            _ => panic!("Invalid hdu type found"),
        };

    match status {
        0 => Ok(hdu_type),
        _ => {
            Err(FitsError {
                status: status,
                message: stringutils::status_to_string(status).unwrap(),
            })
        }
    }
}

impl FitsFile {
    pub fn open(filename: &str) -> Result<Self> {
        let mut fptr = ptr::null_mut();
        let mut status = 0;
        let c_filename = ffi::CString::new(filename).unwrap();

        unsafe {
            sys::ffopen(&mut fptr as *mut *mut sys::fitsfile,
                        c_filename.as_ptr(),
                        sys::FileOpenMode::READONLY as libc::c_int,
                        &mut status);
        }

        match status {
            0 => {
                Ok(FitsFile {
                    fptr: fptr,
                    filename: filename.to_string(),
                })
            }
            status => {
                Err(FitsError {
                    status: status,
                    message: stringutils::status_to_string(status).unwrap(),
                })
            }
        }

    }

    pub fn create(path: &str) -> Result<Self> {
        let mut fptr = ptr::null_mut();
        let mut status = 0;
        let c_filename = ffi::CString::new(path).unwrap();

        unsafe {
            sys::ffinit(&mut fptr as *mut *mut sys::fitsfile,
                        c_filename.as_ptr(),
                        &mut status);
        }

        match status {
            0 => {
                Ok(FitsFile {
                    fptr: fptr,
                    filename: path.to_string(),
                })
            }
            status => {
                Err(FitsError {
                    status: status,
                    message: stringutils::status_to_string(status).unwrap(),
                })
            }
        }
    }

    pub fn change_hdu<T: DescribesHdu>(&self, hdu_description: T) -> Result<()> {
        hdu_description.change_hdu(self)
    }

    fn hdu_number(&self) -> usize {
        let mut hdu_num = 0;
        unsafe {
            sys::ffghdn(self.fptr, &mut hdu_num);
        }
        (hdu_num - 1) as usize
    }

    pub fn read_key<T: ReadsKey>(&self, name: &str) -> Result<T> {
        T::read_key(self, name)
    }

    fn fetch_hdu_info(&self) -> Result<HduInfo> {
        unsafe { fetch_hdu_info(self.fptr) }
    }
}

impl Drop for FitsFile {
    fn drop(&mut self) {
        let mut status = 0;
        unsafe {
            sys::ffclos(self.fptr, &mut status);
        }
    }
}

#[cfg(test)]
mod test {
    extern crate tempdir;
    use super::*;
    use sys;
    use super::typechar_to_data_type;

    #[test]
    fn typechar_conversions() {
        let input = vec![
            "X",
            "B",
            "L",
            "A",
            "I",
            "J",
            "E",
            "D",
            "C",
            "M",
        ];
        let expected = vec![
            sys::DataType::TBIT,
            sys::DataType::TBYTE,
            sys::DataType::TLOGICAL,
            sys::DataType::TSTRING,
            sys::DataType::TSHORT,
            sys::DataType::TLONG,
            sys::DataType::TFLOAT,
            sys::DataType::TDOUBLE,
            sys::DataType::TCOMPLEX,
            sys::DataType::TDBLCOMPLEX,
        ];

        input.iter()
            .zip(expected)
            .map(|(&i, e)| {
                assert_eq!(typechar_to_data_type(i), e);
            })
            .collect::<Vec<_>>();
    }

    #[test]
    fn opening_an_existing_file() {
        match FitsFile::open("../testdata/full_example.fits") {
            Ok(_) => {}
            Err(e) => panic!("{:?}", e),
        }
    }

    #[test]
    fn creating_a_new_file() {
        let tdir = tempdir::TempDir::new("fitsio-").unwrap();
        let tdir_path = tdir.path();
        let filename = tdir_path.join("test.fits");
        assert!(!filename.exists());

        match FitsFile::create(filename.to_str().unwrap()) {
            Ok(_) => assert!(filename.exists()),
            Err(e) => panic!("Error: {:?}", e),
        }
    }

    #[test]
    fn fetching_a_hdu() {
        let f = FitsFile::open("../testdata/full_example.fits").unwrap();
        for i in 0..2 {
            f.change_hdu(i).unwrap();
            assert_eq!(f.hdu_number(), i);
        }

        match f.change_hdu(2) {
            Err(e) => assert_eq!(e.status, 107),
            _ => panic!("Error checking for failure"),
        }

        f.change_hdu("TESTEXT").unwrap();
        assert_eq!(f.hdu_number(), 1);
    }

    #[test]
    fn reading_header_keys() {
        let f = FitsFile::open("../testdata/full_example.fits").unwrap();
        match f.read_key::<i64>("INTTEST") {
            Ok(value) => assert_eq!(value, 42),
            Err(e) => panic!("Error reading key: {:?}", e),
        }

        match f.read_key::<f64>("DBLTEST") {
            Ok(value) => assert_eq!(value, 0.09375),
            Err(e) => panic!("Error reading key: {:?}", e),
        }

        match f.read_key::<String>("TEST") {
            Ok(value) => assert_eq!(value, "value"),
            Err(e) => panic!("Error reading key: {:?}", e),
        }
    }
}
<commit_msg>Add fetching HDU type<commit_after>#![allow(dead_code, unused_imports)]

extern crate fitsio_sys as sys;
extern crate libc;

use std::ptr;
use std::ffi;

mod stringutils;

/// Error type
#[derive(Debug, PartialEq, Eq)]
pub struct FitsError {
    status: i32,
    message: String,
}

pub type Result<T> = std::result::Result<T, FitsError>;

/// Hdu description type
///
/// Any way of describing a HDU - number or string which either
/// changes the hdu by absolute number, or by name.
pub trait DescribesHdu {
    fn change_hdu(&self, fptr: &FitsFile) -> Result<()>;
}

impl DescribesHdu for usize {
    fn change_hdu(&self, f: &FitsFile) -> Result<()> {
        let mut _hdu_type = 0;
        let mut status = 0;
        unsafe {
            sys::ffmahd(f.fptr, (*self + 1) as i32, &mut _hdu_type, &mut status);
        }
        match status {
            0 => Ok(()),
            _ => {
                Err(FitsError {
                    status: status,
                    message: stringutils::status_to_string(status).unwrap(),
                })
            }
        }
    }
}

impl<'a> DescribesHdu for &'a str {
    fn change_hdu(&self, f: &FitsFile) -> Result<()> {
        let mut _hdu_type = 0;
        let mut status = 0;
        let c_hdu_name = ffi::CString::new(*self).unwrap();

        unsafe {
            sys::ffmnhd(f.fptr,
                        sys::HduType::ANY_HDU as libc::c_int,
                        c_hdu_name.into_raw(),
                        0,
                        &mut status);
        }

        match status {
            0 => Ok(()),
            _ => {
                Err(FitsError {
                    status: status,
                    message: stringutils::status_to_string(status).unwrap(),
                })
            }
        }
    }
}

/// Trait applied to types which can be read from a FITS header
///
/// This is currently:
///
/// * i32
/// * i64
/// * f32
/// * f64
/// * String
pub trait ReadsKey {
    fn read_key(f: &FitsFile, name: &str) -> Result<Self> where Self: std::marker::Sized;
}

macro_rules! reads_key_impl {
    ($t:ty, $func:ident) => (
        impl ReadsKey for $t {
            fn read_key(f: &FitsFile, name: &str) -> Result<Self> {
                let c_name = ffi::CString::new(name).unwrap();
                let mut status = 0;
                let mut value: Self = Self::default();

                unsafe {
                    sys::$func(f.fptr,
                           c_name.into_raw(),
                           &mut value,
                           ptr::null_mut(),
                           &mut status);
                }

                match status {
                    0 => Ok(value),
                    s => {
                        Err(FitsError {
                            status: s,
                            message: stringutils::status_to_string(s).unwrap(),
                        })
                    }
                }
            }
        }
    )
}

reads_key_impl!(i32, ffgkyl);
reads_key_impl!(i64, ffgkyj);
reads_key_impl!(f32, ffgkye);
reads_key_impl!(f64, ffgkyd);

impl ReadsKey for String {
    fn read_key(f: &FitsFile, name: &str) -> Result<Self> {
        let c_name = ffi::CString::new(name).unwrap();
        let mut status = 0;
        let mut value: Vec<libc::c_char> = vec![0; sys::MAX_VALUE_LENGTH];

        unsafe {
            sys::ffgkys(f.fptr,
                        c_name.into_raw(),
                        value.as_mut_ptr(),
                        ptr::null_mut(),
                        &mut status);
        }

        match status {
            0 => {
                let value: Vec<u8> = value.iter()
                    .map(|&x| x as u8)
                    .filter(|&x| x != 0)
                    .collect();
                Ok(String::from_utf8(value).unwrap())
            }
            status => {
                Err(FitsError {
                    status: status,
                    message: stringutils::status_to_string(status).unwrap(),
                })
            }
        }

    }
}

#[derive(PartialEq, Eq, Debug)]
pub enum HduInfo {
    ImageInfo {
        dimensions: usize,
        shape: Vec<usize>,
    },
    TableInfo {
        column_names: Vec<String>,
        column_types: Vec<sys::DataType>,
        num_rows: usize,
    },
}

pub struct FitsFile {
    fptr: *mut sys::fitsfile,
    pub filename: String,
}

fn typechar_to_data_type<T: Into<String>>(typechar: T) -> sys::DataType {
    match typechar.into().as_str() {
        "X" => sys::DataType::TBIT,
        "B" => sys::DataType::TBYTE,
        "L" => sys::DataType::TLOGICAL,
        "A" => sys::DataType::TSTRING,
        "I" => sys::DataType::TSHORT,
        "J" => sys::DataType::TLONG,
        "E" => sys::DataType::TFLOAT,
        "D" => sys::DataType::TDOUBLE,
        "C" => sys::DataType::TCOMPLEX,
        "M" => sys::DataType::TDBLCOMPLEX,
        other => panic!("Unhandled case: {}", other),
    }
}

unsafe fn fetch_hdu_info(fptr: *mut sys::fitsfile) -> Result<HduInfo> {
    let mut status = 0;
    let mut hdu_type = 0;

    sys::ffghdt(fptr, &mut hdu_type, &mut status);
    let hdu_type =
        match hdu_type {
            0 => {
                let mut dimensions = 0;
                sys::ffgidm(fptr, &mut dimensions, &mut status);

                let mut shape = vec![0; dimensions as usize];
                sys::ffgisz(fptr, dimensions, shape.as_mut_ptr(), &mut status);

                HduInfo::ImageInfo {
                    dimensions: dimensions as usize,
                    shape: shape.iter().map(|v| *v as usize).collect(),
                }
            }
            1 | 2 => {
                let mut num_rows = 0;
                sys::ffgnrw(fptr, &mut num_rows, &mut status);

                let mut num_cols = 0;
                sys::ffgncl(fptr, &mut num_cols, &mut status);
                let mut column_names = Vec::with_capacity(num_cols as usize);
                let mut column_types = Vec::with_capacity(num_cols as usize);

                for i in 0..num_cols {
                    let mut name_buffer: Vec<libc::c_char> = vec![0; 71];
                    let mut type_buffer: Vec<libc::c_char> = vec![0; 71];
                    sys::ffgbcl(fptr,
                                (i + 1) as i32,
                                name_buffer.as_mut_ptr(),
                                ptr::null_mut(),
                                type_buffer.as_mut_ptr(),
                                ptr::null_mut(),
                                ptr::null_mut(),
                                ptr::null_mut(),
                                ptr::null_mut(),
                                ptr::null_mut(),
                                &mut status);
                    column_names.push(stringutils::buf_to_string(&name_buffer).unwrap());
                    column_types.push(typechar_to_data_type(stringutils::buf_to_string(&type_buffer)
                            .unwrap()));
                }

                HduInfo::TableInfo {
                    column_names: column_names,
                    column_types: column_types,
                    num_rows: num_rows as usize,
                }
            }
            _ => panic!("Invalid hdu type found"),
        };

    match status {
        0 => Ok(hdu_type),
        _ => {
            Err(FitsError {
                status: status,
                message: stringutils::status_to_string(status).unwrap(),
            })
        }
    }
}

impl FitsFile {
    pub fn open(filename: &str) -> Result<Self> {
        let mut fptr = ptr::null_mut();
        let mut status = 0;
        let c_filename = ffi::CString::new(filename).unwrap();

        unsafe {
            sys::ffopen(&mut fptr as *mut *mut sys::fitsfile,
                        c_filename.as_ptr(),
                        sys::FileOpenMode::READONLY as libc::c_int,
                        &mut status);
        }

        match status {
            0 => {
                Ok(FitsFile {
                    fptr: fptr,
                    filename: filename.to_string(),
                })
            }
            status => {
                Err(FitsError {
                    status: status,
                    message: stringutils::status_to_string(status).unwrap(),
                })
            }
        }

    }

    pub fn create(path: &str) -> Result<Self> {
        let mut fptr = ptr::null_mut();
        let mut status = 0;
        let c_filename = ffi::CString::new(path).unwrap();

        unsafe {
            sys::ffinit(&mut fptr as *mut *mut sys::fitsfile,
                        c_filename.as_ptr(),
                        &mut status);
        }

        match status {
            0 => {
                Ok(FitsFile {
                    fptr: fptr,
                    filename: path.to_string(),
                })
            }
            status => {
                Err(FitsError {
                    status: status,
                    message: stringutils::status_to_string(status).unwrap(),
                })
            }
        }
    }

    pub fn change_hdu<T: DescribesHdu>(&self, hdu_description: T) -> Result<()> {
        hdu_description.change_hdu(self)
    }

    pub fn hdu_type(&self) -> Result<sys::HduType> {
        let mut status = 0;
        let mut hdu_type = 0;
        unsafe {
            sys::ffghdt(self.fptr, &mut hdu_type, &mut status);
        }
        match status {
            0 => {
                match hdu_type {
                    0 => Ok(sys::HduType::IMAGE_HDU),
                    2 => Ok(sys::HduType::BINARY_TBL),
                    _ => unimplemented!(),
                }
            },
            _ => Err(FitsError {
                status: status,
                message: stringutils::status_to_string(status).unwrap(),
            }),
        }
    }

    fn hdu_number(&self) -> usize {
        let mut hdu_num = 0;
        unsafe {
            sys::ffghdn(self.fptr, &mut hdu_num);
        }
        (hdu_num - 1) as usize
    }

    pub fn read_key<T: ReadsKey>(&self, name: &str) -> Result<T> {
        T::read_key(self, name)
    }

    fn fetch_hdu_info(&self) -> Result<HduInfo> {
        unsafe { fetch_hdu_info(self.fptr) }
    }
}

impl Drop for FitsFile {
    fn drop(&mut self) {
        let mut status = 0;
        unsafe {
            sys::ffclos(self.fptr, &mut status);
        }
    }
}

#[cfg(test)]
mod test {
    extern crate tempdir;
    use super::*;
    use sys;
    use super::typechar_to_data_type;

    #[test]
    fn typechar_conversions() {
        let input = vec![
            "X",
            "B",
            "L",
            "A",
            "I",
            "J",
            "E",
            "D",
            "C",
            "M",
        ];
        let expected = vec![
            sys::DataType::TBIT,
            sys::DataType::TBYTE,
            sys::DataType::TLOGICAL,
            sys::DataType::TSTRING,
            sys::DataType::TSHORT,
            sys::DataType::TLONG,
            sys::DataType::TFLOAT,
            sys::DataType::TDOUBLE,
            sys::DataType::TCOMPLEX,
            sys::DataType::TDBLCOMPLEX,
        ];

        input.iter()
            .zip(expected)
            .map(|(&i, e)| {
                assert_eq!(typechar_to_data_type(i), e);
            })
            .collect::<Vec<_>>();
    }

    #[test]
    fn opening_an_existing_file() {
        match FitsFile::open("../testdata/full_example.fits") {
            Ok(_) => {}
            Err(e) => panic!("{:?}", e),
        }
    }

    #[test]
    fn creating_a_new_file() {
        let tdir = tempdir::TempDir::new("fitsio-").unwrap();
        let tdir_path = tdir.path();
        let filename = tdir_path.join("test.fits");
        assert!(!filename.exists());

        match FitsFile::create(filename.to_str().unwrap()) {
            Ok(_) => assert!(filename.exists()),
            Err(e) => panic!("Error: {:?}", e),
        }
    }

    #[test]
    fn fetching_a_hdu() {
        let f = FitsFile::open("../testdata/full_example.fits").unwrap();
        for i in 0..2 {
            f.change_hdu(i).unwrap();
            assert_eq!(f.hdu_number(), i);
        }

        match f.change_hdu(2) {
            Err(e) => assert_eq!(e.status, 107),
            _ => panic!("Error checking for failure"),
        }

        f.change_hdu("TESTEXT").unwrap();
        assert_eq!(f.hdu_number(), 1);
    }

    #[test]
    fn reading_header_keys() {
        let f = FitsFile::open("../testdata/full_example.fits").unwrap();
        match f.read_key::<i64>("INTTEST") {
            Ok(value) => assert_eq!(value, 42),
            Err(e) => panic!("Error reading key: {:?}", e),
        }

        match f.read_key::<f64>("DBLTEST") {
            Ok(value) => assert_eq!(value, 0.09375),
            Err(e) => panic!("Error reading key: {:?}", e),
        }

        match f.read_key::<String>("TEST") {
            Ok(value) => assert_eq!(value, "value"),
            Err(e) => panic!("Error reading key: {:?}", e),
        }
    }

    #[test]
    fn getting_hdu_type() {
        let f = FitsFile::open("../testdata/full_example.fits").unwrap();
        assert_eq!(f.hdu_type().unwrap(), sys::HduType::IMAGE_HDU);

        f.change_hdu("TESTEXT").unwrap();
        assert_eq!(f.hdu_type().unwrap(), sys::HduType::BINARY_TBL);
    }
}
<|endoftext|>


<commit_before>use std::sync::atomic::AtomicBool;

// This file is part of the uutils coreutils package.
//
// (c) Alex Lyon <arcterus@mail.com>
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.

/// Whether we were called as a multicall binary ("coreutils <utility>")
pub static UTILITY_IS_SECOND_ARG: AtomicBool = AtomicBool::new(false);

//====

#[macro_export]
macro_rules! show(
    ($err:expr) => ({
        let e = $err;
        $crate::error::set_exit_code(e.code());
        eprintln!("{}: {}", $crate::util_name(), e);
    })
);

#[macro_export]
macro_rules! show_if_err(
    ($res:expr) => ({
        if let Err(e) = $res {
            show!(e);
        }
    })
);

/// Show an error to stderr in a similar style to GNU coreutils.
#[macro_export]
macro_rules! show_error(
    ($($args:tt)+) => ({
        eprint!("{}: ", $crate::util_name());
        eprintln!($($args)+);
    })
);

/// Show a warning to stderr in a similar style to GNU coreutils.
#[macro_export]
macro_rules! show_error_custom_description (
    ($err:expr,$($args:tt)+) => ({
        eprint!("{}: {}: ", $crate::util_name(), $err);
        eprintln!($($args)+);
    })
);

#[macro_export]
macro_rules! show_warning(
    ($($args:tt)+) => ({
        eprint!("{}: warning: ", $crate::util_name());
        eprintln!($($args)+);
    })
);

/// Show a bad invocation help message in a similar style to GNU coreutils.
#[macro_export]
macro_rules! show_usage_error(
    ($($args:tt)+) => ({
        eprint!("{}: ", $crate::util_name());
        eprintln!($($args)+);
        eprintln!("Try '{} --help' for more information.", $crate::execution_phrase());
    })
);

//====

/// Calls `exit()` with the provided exit code.
#[macro_export]
macro_rules! exit(
    ($exit_code:expr) => ({
        ::std::process::exit($exit_code)
    })
);

/// Display the provided error message, then `exit()` with the provided exit code
#[macro_export]
macro_rules! crash(
    ($exit_code:expr, $($args:tt)+) => ({
        $crate::show_error!($($args)+);
        $crate::exit!($exit_code)
    })
);

/// Unwraps the Result. Instead of panicking, it exists the program with the
/// provided exit code.
#[macro_export]
macro_rules! crash_if_err(
    ($exit_code:expr, $exp:expr) => (
        match $exp {
            Ok(m) => m,
            Err(f) => $crate::crash!($exit_code, "{}", f),
        }
    )
);

//====

#[macro_export]
macro_rules! safe_write(
    ($fd:expr, $($args:tt)+) => (
        match write!($fd, $($args)+) {
            Ok(_) => {}
            Err(f) => panic!("{}", f)
        }
    )
);

#[macro_export]
macro_rules! safe_writeln(
    ($fd:expr, $($args:tt)+) => (
        match writeln!($fd, $($args)+) {
            Ok(_) => {}
            Err(f) => panic!("{}", f)
        }
    )
);

//-- message templates

//-- message templates : (join utility sub-macros)

#[macro_export]
macro_rules! snippet_list_join_oxford_comma {
    ($conjunction:expr, $valOne:expr, $valTwo:expr) => (
        format!("{}, {} {}", $valOne, $conjunction, $valTwo)
    );
    ($conjunction:expr, $valOne:expr, $valTwo:expr $(, $remaining_values:expr)*) => (
        format!("{}, {}", $valOne, $crate::snippet_list_join_oxford_comma!($conjunction, $valTwo $(, $remaining_values)*))
    );
}

#[macro_export]
macro_rules! snippet_list_join {
    ($conjunction:expr, $valOne:expr, $valTwo:expr) => (
        format!("{} {} {}", $valOne, $conjunction, $valTwo)
    );
    ($conjunction:expr, $valOne:expr, $valTwo:expr $(, $remaining_values:expr)*) => (
        format!("{}, {}", $valOne, $crate::snippet_list_join_oxford_comma!($conjunction, $valTwo $(, $remaining_values)*))
    );
}

//-- message templates : invalid input

#[macro_export]
macro_rules! msg_invalid_input {
    ($reason: expr) => {
        format!("invalid input: {}", $reason)
    };
}

// -- message templates : invalid input : flag

#[macro_export]
macro_rules! msg_invalid_opt_use {
    ($about:expr, $flag:expr) => {
        $crate::msg_invalid_input!(format!("The '{}' option {}", $flag, $about))
    };
    ($about:expr, $long_flag:expr, $short_flag:expr) => {
        $crate::msg_invalid_input!(format!(
            "The '{}' ('{}') option {}",
            $long_flag, $short_flag, $about
        ))
    };
}

#[macro_export]
macro_rules! msg_opt_only_usable_if {
    ($clause:expr, $flag:expr) => {
        $crate::msg_invalid_opt_use!(format!("only usable if {}", $clause), $flag)
    };
    ($clause:expr, $long_flag:expr, $short_flag:expr) => {
        $crate::msg_invalid_opt_use!(
            format!("only usable if {}", $clause),
            $long_flag,
            $short_flag
        )
    };
}

#[macro_export]
macro_rules! msg_opt_invalid_should_be {
    ($expects:expr, $received:expr, $flag:expr) => {
        $crate::msg_invalid_opt_use!(
            format!("expects {}, but was provided {}", $expects, $received),
            $flag
        )
    };
    ($expects:expr, $received:expr, $long_flag:expr, $short_flag:expr) => {
        $crate::msg_invalid_opt_use!(
            format!("expects {}, but was provided {}", $expects, $received),
            $long_flag,
            $short_flag
        )
    };
}

// -- message templates : invalid input : input combinations

#[macro_export]
macro_rules! msg_expects_one_of {
    ($valOne:expr $(, $remaining_values:expr)*) => (
        $crate::msg_invalid_input!(format!("expects one of {}", $crate::snippet_list_join!("or", $valOne $(, $remaining_values)*)))
    );
}

#[macro_export]
macro_rules! msg_expects_no_more_than_one_of {
    ($valOne:expr $(, $remaining_values:expr)*) => (
        $crate::msg_invalid_input!(format!("expects no more than one of {}", $crate::snippet_list_join!("or", $valOne $(, $remaining_values)*))) ;
    );
}
<commit_msg>macros: Add documentation with examples to macros<commit_after>//! Macros for the uucore utilities.
//!
//! This module bundles all macros used across the uucore utilities. These
//! include macros for reporting errors in various formats, aborting program
//! execution and more.
//!
//! To make use of all macros in this module, they must be imported like so:
//!
//! ```ignore
//! #[macro_use]
//! extern crate uucore;
//! ```
//!
//! Alternatively, you can import single macros by importing them through their
//! fully qualified name like this:
//!
//! ```no_run
//! use uucore::{show, crash};
//! ```
//!
//! Here's an overview of the macros sorted by purpose
//!
//! - Print errors
//!   - From types implementing [`crate::error::UError`]: [`show!`],
//!     [`show_if_err!`]
//!   - From custom messages: [`show_error!`], [`show_usage_error!`]
//! - Print warnings: [`show_warning!`]
//! - Terminate util execution
//!   - Terminate regularly: [`exit!`], [`return_if_err!`]
//!   - Crash program: [`crash!`], [`crash_if_err!`], [`safe_unwrap!`]
//! - Unwrapping result types: [`safe_unwrap!`]

// spell-checker:ignore sourcepath targetpath

use std::sync::atomic::AtomicBool;

// This file is part of the uutils coreutils package.
//
// (c) Alex Lyon <arcterus@mail.com>
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.

/// Whether we were called as a multicall binary ("coreutils <utility>")
pub static UTILITY_IS_SECOND_ARG: AtomicBool = AtomicBool::new(false);

//====

/// Display a [`crate::error::UError`] and set global exit code.
///
/// Prints the error message contained in an [`crate::error::UError`] to stderr
/// and sets the exit code through [`crate::error::set_exit_code`]. The printed
/// error message is prepended with the calling utility's name. A call to this
/// macro will not finish program execution.
///
/// # Examples
///
/// The following example would print a message "Some error occurred" and set
/// the utility's exit code to 2.
///
/// ```
/// # #[macro_use]
/// # extern crate uucore;
///
/// use uucore::error::{self, USimpleError};
///
/// fn main() {
///     let err = USimpleError::new(2, "Some error occurred.");
///     show!(err);
///     assert_eq!(error::get_exit_code(), 2);
/// }
/// ```
///
/// If not using [`crate::error::UError`], one may achieve the same behavior
/// like this:
///
/// ```
/// # #[macro_use]
/// # extern crate uucore;
///
/// use uucore::error::set_exit_code;
///
/// fn main() {
///     set_exit_code(2);
///     show_error!("Some error occurred.");
/// }
/// ```
#[macro_export]
macro_rules! show(
    ($err:expr) => ({
        let e = $err;
        $crate::error::set_exit_code(e.code());
        eprintln!("{}: {}", $crate::util_name(), e);
    })
);

/// Display an error and set global exit code in error case.
///
/// Wraps around [`show!`] and takes a [`crate::error::UResult`] instead of a
/// [`crate::error::UError`] type. This macro invokes [`show!`] if the
/// [`crate::error::UResult`] is an `Err`-variant. This can be invoked directly
/// on the result of a function call, like in the `install` utility:
///
/// ```ignore
/// show_if_err!(copy(sourcepath, &targetpath, b));
/// ```
///
/// # Examples
///
/// ```ignore
/// # #[macro_use]
/// # extern crate uucore;
/// # use uucore::error::{UError, UIoError, UResult, USimpleError};
///
/// # fn main() {
/// let is_ok = Ok(1);
/// // This does nothing at all
/// show_if_err!(is_ok);
///
/// let is_err = Err(USimpleError::new(1, "I'm an error").into());
/// // Calls `show!` on the contained USimpleError
/// show_if_err!(is_err);
/// # }
/// ```
///
///
#[macro_export]
macro_rules! show_if_err(
    ($res:expr) => ({
        if let Err(e) = $res {
            show!(e);
        }
    })
);

/// Show an error to stderr in a similar style to GNU coreutils.
///
/// Takes a [`format!`]-like input and prints it to stderr. The output is
/// prepended with the current utility's name.
///
/// # Examples
///
/// ```
/// # #[macro_use]
/// # extern crate uucore;
/// # fn main() {
/// show_error!("Couldn't apply {} to {}", "foo", "bar");
/// # }
/// ```
#[macro_export]
macro_rules! show_error(
    ($($args:tt)+) => ({
        eprint!("{}: ", $crate::util_name());
        eprintln!($($args)+);
    })
);

/// Show a warning to stderr in a similar style to GNU coreutils.
///
/// Is this really required? Used in the following locations:
///
/// ./src/uu/head/src/head.rs:12
/// ./src/uu/head/src/head.rs:424
/// ./src/uu/head/src/head.rs:427
/// ./src/uu/head/src/head.rs:430
/// ./src/uu/head/src/head.rs:453
/// ./src/uu/du/src/du.rs:339
/// ./src/uu/wc/src/wc.rs:270
/// ./src/uu/wc/src/wc.rs:273
#[macro_export]
macro_rules! show_error_custom_description (
    ($err:expr,$($args:tt)+) => ({
        eprint!("{}: {}: ", $crate::util_name(), $err);
        eprintln!($($args)+);
    })
);

/// Print a warning message to stderr.
///
/// Takes [`format!`]-compatible input and prepends it with the current
/// utility's name and "warning: " before printing to stderr.
///
/// # Examples
///
/// ```
/// # #[macro_use]
/// # extern crate uucore;
/// # fn main() {
/// // outputs <name>: warning: Couldn't apply foo to bar
/// show_warning!("Couldn't apply {} to {}", "foo", "bar");
/// # }
/// ```
#[macro_export]
macro_rules! show_warning(
    ($($args:tt)+) => ({
        eprint!("{}: warning: ", $crate::util_name());
        eprintln!($($args)+);
    })
);

/// Show a bad invocation help message in a similar style to GNU coreutils.
///
/// Takes a [`format!`]-compatible input and prepends it with the current
/// utility's name before printing to stderr.
///
/// # Examples
///
/// ```
/// # #[macro_use]
/// # extern crate uucore;
/// # fn main() {
/// // outputs <name>: Couldn't apply foo to bar
/// //         Try '<name> --help' for more information.
/// show_usage_error!("Couldn't apply {} to {}", "foo", "bar");
/// # }
/// ```
#[macro_export]
macro_rules! show_usage_error(
    ($($args:tt)+) => ({
        eprint!("{}: ", $crate::util_name());
        eprintln!($($args)+);
        eprintln!("Try '{} --help' for more information.", $crate::execution_phrase());
    })
);

//====

/// Calls [`std::process::exit`] with the provided exit code.
///
/// Why not call exit directly?
#[macro_export]
macro_rules! exit(
    ($exit_code:expr) => ({
        ::std::process::exit($exit_code)
    })
);

/// Display an error and [`exit!`]
///
/// Displays the provided error message using [`show_error!`], then invokes
/// [`exit!`] with the provided exit code.
///
/// # Examples
///
/// ```should_panic
/// # #[macro_use]
/// # extern crate uucore;
/// # fn main() {
/// // outputs <name>: Couldn't apply foo to bar
/// // and terminates execution
/// crash!(1, "Couldn't apply {} to {}", "foo", "bar");
/// # }
/// ```
#[macro_export]
macro_rules! crash(
    ($exit_code:expr, $($args:tt)+) => ({
        $crate::show_error!($($args)+);
        $crate::exit!($exit_code)
    })
);

/// Unwrap a [`std::result::Result`], crashing instead of panicking.
///
/// If the result is an `Ok`-variant, returns the value contained inside. If it
/// is an `Err`-variant, invokes [`crash!`] with the formatted error instead.
///
/// # Examples
///
/// ```should_panic
/// # #[macro_use]
/// # extern crate uucore;
/// # fn main() {
/// let is_ok: Result<u32, &str> = Ok(1);
/// // Does nothing
/// crash_if_err!(1, is_ok);
///
/// let is_err: Result<u32, &str> = Err("This didn't work...");
/// // Calls `crash!`
/// crash_if_err!(1, is_err);
/// # }
/// ```
#[macro_export]
macro_rules! crash_if_err(
    ($exit_code:expr, $exp:expr) => (
        match $exp {
            Ok(m) => m,
            Err(f) => $crate::crash!($exit_code, "{}", f),
        }
    )
);

/// Unwrap some Result, crashing instead of panicking.
///
/// Drop this in favor of `crash_if_err!`
#[macro_export]
macro_rules! safe_unwrap(
    ($exp:expr) => (
        match $exp {
            Ok(m) => m,
            Err(f) => $crate::crash!(1, "{}", f.to_string())
        }
    )
);

//====

/// Unwraps the Result. Instead of panicking, it shows the error and then
/// returns from the function with the provided exit code.
/// Assumes the current function returns an i32 value.
///
/// Replace with `crash_if_err`?
#[macro_export]
macro_rules! return_if_err(
    ($exit_code:expr, $exp:expr) => (
        match $exp {
            Ok(m) => m,
            Err(f) => {
                $crate::show_error!("{}", f);
                return $exit_code;
            }
        }
    )
);

//====

/// This is used exclusively by du...
#[macro_export]
macro_rules! safe_writeln(
    ($fd:expr, $($args:tt)+) => (
        match writeln!($fd, $($args)+) {
            Ok(_) => {}
            Err(f) => panic!("{}", f)
        }
    )
);

//-- message templates

//-- message templates : (join utility sub-macros)

// used only by "cut"
#[macro_export]
macro_rules! snippet_list_join_oxford_comma {
    ($conjunction:expr, $valOne:expr, $valTwo:expr) => (
        format!("{}, {} {}", $valOne, $conjunction, $valTwo)
    );
    ($conjunction:expr, $valOne:expr, $valTwo:expr $(, $remaining_values:expr)*) => (
        format!("{}, {}", $valOne, $crate::snippet_list_join_oxford_comma!($conjunction, $valTwo $(, $remaining_values)*))
    );
}

// used only by "cut"
#[macro_export]
macro_rules! snippet_list_join {
    ($conjunction:expr, $valOne:expr, $valTwo:expr) => (
        format!("{} {} {}", $valOne, $conjunction, $valTwo)
    );
    ($conjunction:expr, $valOne:expr, $valTwo:expr $(, $remaining_values:expr)*) => (
        format!("{}, {}", $valOne, $crate::snippet_list_join_oxford_comma!($conjunction, $valTwo $(, $remaining_values)*))
    );
}

//-- message templates : invalid input

#[macro_export]
macro_rules! msg_invalid_input {
    ($reason: expr) => {
        format!("invalid input: {}", $reason)
    };
}

// -- message templates : invalid input : flag

#[macro_export]
macro_rules! msg_invalid_opt_use {
    ($about:expr, $flag:expr) => {
        $crate::msg_invalid_input!(format!("The '{}' option {}", $flag, $about))
    };
    ($about:expr, $long_flag:expr, $short_flag:expr) => {
        $crate::msg_invalid_input!(format!(
            "The '{}' ('{}') option {}",
            $long_flag, $short_flag, $about
        ))
    };
}

// Only used by "cut"
#[macro_export]
macro_rules! msg_opt_only_usable_if {
    ($clause:expr, $flag:expr) => {
        $crate::msg_invalid_opt_use!(format!("only usable if {}", $clause), $flag)
    };
    ($clause:expr, $long_flag:expr, $short_flag:expr) => {
        $crate::msg_invalid_opt_use!(
            format!("only usable if {}", $clause),
            $long_flag,
            $short_flag
        )
    };
}

// Used only by "cut"
#[macro_export]
macro_rules! msg_opt_invalid_should_be {
    ($expects:expr, $received:expr, $flag:expr) => {
        $crate::msg_invalid_opt_use!(
            format!("expects {}, but was provided {}", $expects, $received),
            $flag
        )
    };
    ($expects:expr, $received:expr, $long_flag:expr, $short_flag:expr) => {
        $crate::msg_invalid_opt_use!(
            format!("expects {}, but was provided {}", $expects, $received),
            $long_flag,
            $short_flag
        )
    };
}

// -- message templates : invalid input : input combinations

// UNUSED!
#[macro_export]
macro_rules! msg_expects_one_of {
    ($valOne:expr $(, $remaining_values:expr)*) => (
        $crate::msg_invalid_input!(format!("expects one of {}", $crate::snippet_list_join!("or", $valOne $(, $remaining_values)*)))
    );
}

// Used only by "cut"
#[macro_export]
macro_rules! msg_expects_no_more_than_one_of {
    ($valOne:expr $(, $remaining_values:expr)*) => (
        $crate::msg_invalid_input!(format!("expects no more than one of {}", $crate::snippet_list_join!("or", $valOne $(, $remaining_values)*))) ;
    );
}
<|endoftext|>