extern crate cpr;
extern crate scoped_threadpool;
extern crate getopts;
extern crate bio;
extern crate num_cpus;
extern crate time;
use std::env;
use cpr::cpr;
use getopts::Options;
use std::path::Path;
use bio::io::fasta::Reader;
use scoped_threadpool::Pool;
use std::io::prelude::*;
use std::io::{BufReader, BufWriter};
use std::fs::File;
use time::now;
use std::fs::{remove_dir_all, create_dir};
type Arg = String;
type ThrdNm = u32;
const DFLT_MX_SPN: usize = 200;
fn main() {
let args = env::args().collect::<Vec<Arg>>();
let prgrm = args[0].clone();
let mut opts = Options::new();
opts.reqopt("i", "", "Input RNA seqs in single file of FASTA format", "STR");
opts.reqopt("o", "", "Output prob. dist. seqs in single file of tabular format", "STR");
opts.optopt("m", "", &format!("Max. span between paired bases (Default: {})", DFLT_MX_SPN), "UINT");
opts.optopt("t", "", "# of threads in multithreading (Default: system val.)", "UINT");
opts.optflag("a", "", "Approximate estimation");
opts.optflag("h", "help", "Print help menu");
let mtchs = match opts.parse(&args[1 ..]) {
Ok(mtch) => {mtch}
Err(fl) => {prnt_usg(&prgrm, &opts); panic!(fl.to_string())}
};
if mtchs.opt_present("h") {
prnt_usg(&prgrm, &opts);
return;
}
let i = mtchs.opt_str("i").expect("Failed to retrieve input file from command args.");
let o = mtchs.opt_str("o").expect("Failed to retrieve output file from command args.");
let m = if mtchs.opt_present("m") {
mtchs.opt_str("m").expect("Failed to retrieve max. span between paired bases from command args.").parse().expect("Failed to parse max. span between paired bases.")
} else {
DFLT_MX_SPN
};
let a = mtchs.opt_present("a");
let t = if mtchs.opt_present("t") {
mtchs.opt_str("t").expect("Failed to retrieve # of threads from command args failed.").parse().expect("Failed to parse # of threads.")
} else {
num_cpus::get() as ThrdNm
};
let fasta_rdr = Reader::from_file(Path::new(&i)).ok().expect("Failed to read FASTA file.");
let tm_stmp = gt_tm_stmp();
let tmp_dr = String::from("/tmp/cpr_") + &tm_stmp;
let tmp_dr = Path::new(&tmp_dr);
if !tmp_dr.exists() {
let _ = create_dir(tmp_dr);
}
let mut thrd_pl = Pool::new(t);
thrd_pl.scoped(|scp| {
for rc in fasta_rdr.records() {
scp.execute(|| {
let dt = rc.ok().expect("Failed to read FASTA record.");
let sq = dt.seq().to_vec();
let id = dt.id().expect("Failed to get FASTA record ID.");
let cntxt_dst_sq = cpr(&sq, m, a);
let mut tmp_otpt_fl = BufWriter::new(File::create(tmp_dr.join(&(String::from(id) + ".dat")).to_str().expect("Failed to parse temp. file path.")).expect("Failed to create temp. output file."));
let _ = tmp_otpt_fl.write_all((String::from(">") + id + "\n").as_bytes());
for cntxt_dst in &cntxt_dst_sq {
let mut bfr = cntxt_dst.iter().fold(String::new(), |acmltr, prb| acmltr + &format!("{:e} ", prb));
bfr.pop();
bfr += "\n";
let _ = tmp_otpt_fl.write_all(bfr.as_bytes());
}
let _ = tmp_otpt_fl.write_all(b"\n");
});
}
});
let mut otpt_fl = BufWriter::new(File::create(Path::new(&o)).expect("Failed to create output file."));
let _ = otpt_fl.write_all(b"# CapR version 1.1.0\n# Format = {bulge prob.} {internal prob.} {hairpin prob.} {exterior prob.} {multi prob.} {stem prob.} for the start to the end of each seq.\n");
for prb_dst_sq in tmp_dr.read_dir().ok().expect("Failed to read entries within temp. dir.") {
let prb_dst_sq = prb_dst_sq.ok().expect("Failed to read entry within temp. dir.");
let mut prb_dst_sq = BufReader::new(File::open(prb_dst_sq.path()).expect("Failed to open entry within temp. dir."));
let mut bfr = Vec::new();
let _ = prb_dst_sq.read_to_end(&mut bfr);
let _ = otpt_fl.write_all(&bfr);
}
let _ = remove_dir_all(tmp_dr);
}
#[inline]
fn prnt_usg(prgrm: &str, opts: &Options) {
let brf = format!("Usage: {} [options]", prgrm);
print!("{}", opts.usage(&brf));
}
#[inline]
fn gt_tm_stmp() -> String {
let nw = now();
format!("{}-{}-{}-{}:{}:{}", nw.tm_year + 1900, nw.tm_mon + 1, nw.tm_mday, nw.tm_hour, nw.tm_min, nw.tm_sec)
}