spirq-dis 0.1.4

SPIR-V disassembler
use clap::Parser;
use spirq_spvasm::{Disassembler, SpirvBinary};
use std::{
    fs::File,
    io::{stderr, Read, Write},
    path::Path,
    process::exit,
};

#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
struct Args {
    #[arg(help = "Input SPIR-V assembly file path. Or read from stdin if input \
        file path is not provided.")]
    in_path: Option<String>,

    #[arg(
        short,
        long,
        help = "Output SPIR-V assembly file path. The output is printed to \
        stdout if this path is not given."
    )]
    out_path: Option<String>,

    #[arg(long, help = "Don't indent instructions.")]
    no_indent: bool,

    #[arg(long, help = "Don't output the header as leading comments.")]
    no_header: bool,

    #[arg(long, help = "Show raw Id values instead of friendly names.")]
    raw_id: bool,
}

fn main() {
    let args = Args::parse();

    let mut in_file: Box<dyn Read> = if let Some(in_path) = &args.in_path {
        let in_path = Path::new(in_path);
        let in_file = File::open(in_path).unwrap_or_else(|e| {
            writeln!(stderr(), "error: failed to open input file: {}", e).unwrap();
            exit(1);
        });
        let in_file: Box<dyn Read> = Box::new(in_file);
        in_file
    } else {
        let stdin = std::io::stdin();
        let in_file = Box::new(stdin);
        in_file
    };

    let mut spv = Vec::new();
    in_file.read_to_end(&mut spv).unwrap_or_else(|e| {
        writeln!(stderr(), "error: failed to read input file: {}", e).unwrap();
        exit(1);
    });

    let dis = Disassembler::new()
        .print_header(!args.no_header)
        .indent(!args.no_indent)
        .name_ids(!args.raw_id)
        .name_type_ids(!args.raw_id)
        .name_const_ids(!args.raw_id);
    let spvasm = dis
        .disassemble(&SpirvBinary::from(spv))
        .unwrap_or_else(|e| {
            writeln!(stderr(), "error: failed to read input file: {}", e).unwrap();
            exit(1);
        });

    if let Some(out_path) = args.out_path {
        let out_path = Path::new(&out_path).to_owned();
        let mut out_file = File::create(out_path).unwrap_or_else(|e| {
            writeln!(stderr(), "error: failed to open output file: {}", e).unwrap();
            exit(1);
        });
        out_file
            .write_all(&spvasm.into_bytes())
            .unwrap_or_else(|e| {
                writeln!(stderr(), "error: failed to write output file: {}", e).unwrap();
                exit(1);
            });
    } else {
        println!("{}", spvasm);
    };
}