cpr 1.1.0

CapR, Efficient RNA Context Probability Estimator
Documentation
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)
}