use anyhow::anyhow;
use chrono::{DateTime, Local};
use std::env;
use std::{fmt::Debug, str::FromStr, time};
use uuid::Uuid;
pub fn command_line_str() -> String {
let args: Vec<String> = env::args().collect();
args.join(" ")
}
#[allow(unused)]
pub fn range_parser<T>(range_str: &str) -> Vec<(T, T)>
where
T: FromStr,
<T as FromStr>::Err: Debug,
{
range_str
.trim()
.split(",")
.map(|single_range| {
let items = single_range
.trim()
.split(":")
.filter(|item| item.trim().len() != 0)
.collect::<Vec<_>>();
return if items.len() == 2 {
(
items[0].parse::<T>().expect(&format!("{}", items[0])),
items[1].parse::<T>().expect(&format!("{}", items[1])),
)
} else {
(
items[0].parse::<T>().expect(&format!("{}", items[0])),
items[0].parse::<T>().expect(&format!("{}", items[0])),
)
};
})
.collect::<Vec<_>>()
}
#[derive(Debug, Clone)]
pub struct Range<T> {
range: Vec<(T, T)>,
}
impl<T> Range<T>
where
T: PartialOrd,
T: FromStr,
<T as FromStr>::Err: Debug,
{
pub fn new(range_str: &str) -> Self {
Self {
range: range_parser::<T>(range_str),
}
}
pub fn within_range(&self, v: T) -> bool {
let mut result = false;
for (b, e) in &self.range {
if *b <= v && v <= *e {
result = true;
break;
}
}
result
}
}
#[allow(unused)]
#[derive(Debug)]
pub struct ScopedTimer {
iter: usize,
elapsed: u128, }
#[allow(unused)]
impl ScopedTimer {
pub fn new() -> Self {
ScopedTimer {
iter: 0,
elapsed: 0,
}
}
pub fn perform_timing(&mut self) -> Timer<'_> {
Timer::new(self)
}
pub fn reset(&mut self) {
self.iter = 0;
self.elapsed = 0;
}
pub fn speed(&self, multiplier: Option<u128>) -> f64 {
let multiplier = multiplier.unwrap_or(1);
assert!(multiplier > 0);
self.iter as f64 / (self.elapsed as f64 / multiplier as f64)
}
}
impl ToString for ScopedTimer {
fn to_string(&self) -> String {
format!(
"{:.10} iter/nano_secs",
(self.iter as f64 / self.elapsed as f64)
)
}
}
pub struct Timer<'a> {
scoped_timer: &'a mut ScopedTimer,
instant: time::Instant,
}
#[allow(unused)]
impl<'a> Timer<'a> {
fn new(scoped_timer: &'a mut ScopedTimer) -> Self {
let instant = time::Instant::now();
Timer {
scoped_timer: scoped_timer,
instant: instant,
}
}
pub fn done_with_cnt(mut self, cnt: usize) {
let elapsed = self.instant.elapsed().as_nanos();
self.scoped_timer.iter += cnt;
self.scoped_timer.elapsed += elapsed;
}
pub fn speed(&self, multiplier: Option<u128>) -> f64 {
self.scoped_timer.speed(multiplier)
}
}
pub fn generate_tmp_filename(fname: &str) -> String {
let now: DateTime<Local> = Local::now();
let formatted_str = now.format("%Y-%m-%d %H:%M:%S").to_string();
let uuid_v5 = Uuid::new_v5(&Uuid::NAMESPACE_DNS, formatted_str.as_bytes());
return if fname.contains(".") {
let (prefix, suffix) = fname.rsplit_once(".").unwrap();
format!("{}-{}.{}", prefix, uuid_v5, suffix)
} else {
format!("{}-{}", fname, uuid_v5)
};
}
pub enum FastxFile {
Fasta,
Fastq,
}
pub fn fastx_file_fmt(fname: &str) -> anyhow::Result<FastxFile> {
if fname.ends_with("fa") || fname.ends_with("fna") || fname.ends_with("fasta") {
return Ok(FastxFile::Fasta);
}
if fname.ends_with("fastq") || fname.ends_with("fq") {
return Ok(FastxFile::Fastq);
}
return Err(anyhow!("{} is not a fastx file", fname));
}
#[cfg(test)]
mod test {
use super::range_parser;
#[test]
fn test_range_parser() {
eprintln!("{:?}", range_parser::<i32>("1:3,2,4:10"));
eprintln!("{:?}", range_parser::<f32>("1.0:3.2,2.1,4.1:10.4"));
}
}