Skip to main content

rsomics_wig_to_bed/
lib.rs

1use std::fs::File;
2use std::io::{BufRead, BufReader, BufWriter, Write};
3use std::path::Path;
4
5use rsomics_common::{Result, RsomicsError};
6
7pub fn wig_to_bed(input: &Path, threshold: f64, output: &mut dyn Write) -> Result<u64> {
8    let file = File::open(input)
9        .map_err(|e| RsomicsError::InvalidInput(format!("{}: {e}", input.display())))?;
10    let reader = BufReader::new(file);
11    let mut out = BufWriter::new(output);
12
13    let mut chrom = String::new();
14    let mut pos: u64 = 0;
15    let mut step: u64 = 1;
16    let mut span: u64 = 1;
17    let mut count: u64 = 0;
18
19    for line in reader.lines() {
20        let line = line.map_err(RsomicsError::Io)?;
21        let line = line.trim();
22
23        if line.is_empty() || line.starts_with('#') || line.starts_with("track") {
24            continue;
25        }
26
27        if line.starts_with("fixedStep") || line.starts_with("variableStep") {
28            for part in line.split_whitespace() {
29                if let Some(val) = part.strip_prefix("chrom=") {
30                    chrom = val.to_string();
31                } else if let Some(val) = part.strip_prefix("start=") {
32                    pos = val.parse().unwrap_or(1) - 1;
33                } else if let Some(val) = part.strip_prefix("step=") {
34                    step = val.parse().unwrap_or(1);
35                } else if let Some(val) = part.strip_prefix("span=") {
36                    span = val.parse().unwrap_or(1);
37                }
38            }
39            continue;
40        }
41
42        let parts: Vec<&str> = line.split('\t').collect();
43        if parts.len() >= 4 {
44            let c = parts[0];
45            let s: u64 = parts[1].parse().unwrap_or(0);
46            let e: u64 = parts[2].parse().unwrap_or(0);
47            let v: f64 = parts[3].parse().unwrap_or(0.0);
48            if v >= threshold {
49                writeln!(out, "{c}\t{s}\t{e}\t{v}").map_err(RsomicsError::Io)?;
50                count += 1;
51            }
52        } else if let Ok(val) = line.parse::<f64>() {
53            if val >= threshold {
54                writeln!(out, "{chrom}\t{pos}\t{}\t{val}", pos + span).map_err(RsomicsError::Io)?;
55                count += 1;
56            }
57            pos += step;
58        }
59    }
60
61    out.flush().map_err(RsomicsError::Io)?;
62    Ok(count)
63}