use anyhow::Result;
use flate2::read;
use gzp::deflate::Bgzf; use gzp::BgzfSyncReader;
use gzp::Compression;
use gzp::ZBuilder;
use std::error::Error;
use std::ffi::OsStr;
use std::fs::File;
use std::io::{self, BufRead, BufReader, BufWriter, Write};
use std::path::{Path, PathBuf};
type DynResult<T> = Result<T, Box<dyn Error + 'static>>;
const BUFFER_SIZE: usize = 32 * 1024;
pub fn writer(filename: &str) -> Box<dyn Write> {
let ext = Path::new(filename).extension();
let path = PathBuf::from(filename);
let buffer = get_output(Some(path)).expect("Error: cannot create output file");
if ext == Some(OsStr::new("gz")) {
let writer = ZBuilder::<Bgzf, _>::new()
.num_threads(8)
.compression_level(Compression::new(6))
.from_writer(buffer);
Box::new(writer)
} else {
buffer
}
}
pub fn reader(filename: &str) -> Box<dyn BufRead + Send + 'static> {
let ext = Path::new(filename).extension();
let path = PathBuf::from(filename);
if ext == Some(OsStr::new("gz")) {
let file = match File::open(&path) {
Err(why) => panic!("couldn't open {}: {}", path.display(), why),
Ok(file) => file,
};
Box::new(BufReader::with_capacity(
BUFFER_SIZE,
read::GzDecoder::new(file),
))
} else if ext == Some(OsStr::new("bgz")) {
Box::new(BufReader::new(BgzfSyncReader::new(
get_input(Some(path)).expect("Error: cannot read input file."),
)))
} else {
get_input(Some(path)).expect("Error: cannot read input file")
}
}
fn get_output(path: Option<PathBuf>) -> Result<Box<dyn Write + Send + 'static>> {
let writer: Box<dyn Write + Send + 'static> = match path {
Some(path) => {
if path.as_os_str() == "-" {
Box::new(BufWriter::with_capacity(BUFFER_SIZE, io::stdout()))
} else {
Box::new(BufWriter::with_capacity(BUFFER_SIZE, File::create(path)?))
}
}
None => Box::new(BufWriter::with_capacity(BUFFER_SIZE, io::stdout())),
};
Ok(writer)
}
fn get_input(path: Option<PathBuf>) -> DynResult<Box<dyn BufRead + Send + 'static>> {
let reader: Box<dyn BufRead + Send + 'static> = match path {
Some(path) => {
if path.as_os_str() == "-" {
Box::new(BufReader::with_capacity(BUFFER_SIZE, io::stdin()))
} else {
Box::new(BufReader::with_capacity(BUFFER_SIZE, File::open(path)?))
}
}
None => Box::new(BufReader::with_capacity(BUFFER_SIZE, io::stdin())),
};
Ok(reader)
}