use std::fs::File;
use std::io::{self, BufRead, BufReader};
use std::path::PathBuf;
#[derive(Debug)]
pub struct BedRecord {
pub chrom: String,
pub start: usize,
pub end: usize,
pub name: Option<String>,
}
impl BedRecord {
fn from_str(record: &str) -> Result<Self, &'static str> {
let fields: Vec<&str> = record.split('\t').collect();
if fields.len() < 3 || fields.len() > 4 {
return Err("Incorrect number of fields | 3 or 4 fields allowed.");
}
Ok(Self {
chrom: fields[0].to_string(),
start: fields[1].parse().map_err(|_| "Invalid start value")?,
end: fields[2].parse().map_err(|_| "Invalid end value")?,
name: if fields.len() > 3 && fields[3] != "." {
Some(fields[3].to_string())
} else {
None
},
})
}
}
pub struct BedReader<R: BufRead> {
reader: R,
}
impl BedReader<BufReader<File>> {
pub fn from_path(path: &PathBuf) -> io::Result<Self> {
let file = File::open(path)?;
let reader = BufReader::new(file);
Ok(BedReader { reader })
}
}
impl<R: BufRead> Iterator for BedReader<R> {
type Item = Result<BedRecord, &'static str>;
fn next(&mut self) -> Option<Self::Item> {
let mut line = String::new();
match self.reader.read_line(&mut line) {
Ok(0) => None, Ok(_) => Some(BedRecord::from_str(line.trim_end())),
Err(_) => Some(Err("Error reading line")),
}
}
}