bgzip 0.3.1

Rust implementation of bgzip
Documentation
use clap::Parser;
use std::fs::File;
use std::io::{stdout, BufReader, Read, Seek, SeekFrom, Write};

#[derive(Debug, Parser)]
struct Args {
    #[command()]
    file: String,
    #[arg(short, long)]
    output: Option<String>,
}

fn main() -> anyhow::Result<()> {
    let parser = Args::parse();

    let mut file = BufReader::new(File::open(&parser.file)?);
    let out: Box<dyn Write> = if let Some(out) = parser.output {
        Box::new(File::create(out)?)
    } else {
        Box::new(stdout().lock())
    };
    let mut csv_out = csv::WriterBuilder::new().from_writer(out);

    csv_out.write_record(&[
        "offset",
        "header-size",
        "compressed-size",
        "decompressed-size",
    ])?;

    loop {
        let offset = file.seek(SeekFrom::Current(0))?;
        let header = bgzip::header::BGZFHeader::from_reader(&mut file)?;
        let compressed_size = header.block_size()?;
        file.seek(SeekFrom::Current(compressed_size as i64 - 20 - 6 + 4))?;

        let mut size_buf: [u8; 4] = [0, 0, 0, 0];
        file.read_exact(&mut size_buf)?;
        let uncompressed_size = u32::from_le_bytes(size_buf);
        csv_out.write_record(&[
            format!("{}", offset),
            format!("{}", header.header_size()),
            format!("{}", compressed_size),
            format!("{}", uncompressed_size),
        ])?;

        if uncompressed_size == 0 {
            break;
        }
    }

    Ok(())
}