use anyhow::Result;
use perbase_lib::{
par_granges::{self, RegionProcessor},
position::pileup_position::PileupPosition,
read_filter::ReadFilter,
};
use rust_htslib::bam::{self, Read, pileup::Alignment, record::Record};
use std::path::PathBuf;
struct BasicProcessor<F: ReadFilter> {
bamfile: PathBuf,
read_filter: F,
}
struct BasicReadFilter {
include_flags: u16,
exclude_flags: u16,
min_mapq: u8,
}
impl ReadFilter for BasicReadFilter {
#[inline]
fn filter_read(&self, read: &Record, _alignment: Option<&Alignment>) -> bool {
let flags = read.flags();
(!flags) & &self.include_flags == 0
&& flags & &self.exclude_flags == 0
&& &read.mapq() >= &self.min_mapq
}
}
impl<F: ReadFilter> RegionProcessor for BasicProcessor<F> {
type P = PileupPosition;
fn process_region(&self, tid: u32, start: u32, stop: u32) -> Vec<Self::P> {
let mut reader = bam::IndexedReader::from_path(&self.bamfile).expect("Indexed reader");
let header = reader.header().to_owned();
reader.fetch((tid, start, stop)).expect("Fetched ROI");
let result: Vec<PileupPosition> = reader
.pileup()
.flat_map(|p| {
let pileup = p.expect("Extracted a pileup");
if pileup.pos() >= start && pileup.pos() < stop {
Some(PileupPosition::from_pileup(
pileup,
&header,
&self.read_filter,
None,
))
} else {
None
}
})
.collect();
result
}
}
fn main() -> Result<()> {
let read_filter = BasicReadFilter {
include_flags: 0,
exclude_flags: 3848,
min_mapq: 20,
};
let basic_processor = BasicProcessor {
bamfile: PathBuf::from("test/test.bam"),
read_filter: read_filter,
};
let par_granges_runner = par_granges::ParGranges::new(
PathBuf::from("test/test.bam"), None, Some(PathBuf::from("test/test.bed")), None, true, None, None, None, basic_processor,
);
let receiver = par_granges_runner.process()?;
receiver.into_iter().for_each(|p: PileupPosition| {
println!("{:?}", p);
});
Ok(())
}