use std::sync::Arc;
use std::path::PathBuf;
use super::ConstructFromPath;
use crate::fileformat::shard::ReadPair;
use super::shard::StreamingReadPairReader;
use rust_htslib::bam::Read;
use super::CellID;
use rust_htslib::bam::record::Record as BamRecord;
type ListReadWithBarcode = Arc<(CellID,Arc<Vec<ReadPair>>)>;
#[derive(Debug)]
pub struct BAMStreamingReadPairReader {
reader: rust_htslib::bam::Reader,
last_rp: Option<(Vec<u8>,ReadPair)>,
}
impl BAMStreamingReadPairReader {
pub fn new(fname: &PathBuf) -> anyhow::Result<BAMStreamingReadPairReader> {
let mut reader = rust_htslib::bam::Reader::from_path(&fname)?;
let mut record = BamRecord::new();
if let Some(_r) = reader.read(&mut record) {
let last_rp = read_to_readpair(&record);
Ok(BAMStreamingReadPairReader {
reader: reader,
last_rp: Some(last_rp)
})
} else {
println!("Warning: empty input BAM");
Ok(BAMStreamingReadPairReader {
reader: reader,
last_rp: None
})
}
}
}
impl StreamingReadPairReader for BAMStreamingReadPairReader {
fn get_reads_for_next_cell(
&mut self
) -> anyhow::Result<Option<ListReadWithBarcode>> {
if let Some((current_cell, last_rp)) = self.last_rp.clone() {
let mut reads:Vec<ReadPair> = Vec::new();
reads.push(last_rp);
self.last_rp = None;
let mut record = BamRecord::new();
while let Some(_r) = self.reader.read(&mut record) {
let (cell_id, rp) = read_to_readpair(&record);
if cell_id == current_cell {
reads.push(rp);
} else {
self.last_rp = Some((
cell_id.to_vec(),
rp
));
break;
}
}
let reads = Arc::new(reads);
let cellid_reads = (
String::from_utf8(current_cell).unwrap(),
reads
);
Ok(Some(Arc::new(cellid_reads)))
} else {
Ok(None)
}
}
}
pub fn readname_to_cell_umi(
read_name: &[u8]
) -> (&[u8], &[u8]) {
let mut splitter = read_name.split(|b| *b == b':');
let mut cell_id = splitter.next().expect("Could not parse cellID from read name");
let umi = splitter.next().expect("Could not parse UMI from read name");
if cell_id.starts_with(b"BASCET_") {
cell_id = &cell_id["BASCET_".len()..];
}
(cell_id, umi)
}
fn read_to_readpair(
record: &BamRecord
) -> (Vec<u8>, ReadPair) {
let (cell_id, umi) = readname_to_cell_umi(record.qname());
let rp = ReadPair {
r1: record.seq().as_bytes(),
r2: Vec::new(),
q1: record.qual().to_vec(),
q2: Vec::new(),
umi: umi.to_vec()
};
(cell_id.to_vec(), rp) }
#[derive(Debug,Clone)]
pub struct BAMStreamingReadPairReaderFactory {
}
impl BAMStreamingReadPairReaderFactory {
pub fn new() -> BAMStreamingReadPairReaderFactory {
BAMStreamingReadPairReaderFactory {}
}
}
impl ConstructFromPath<BAMStreamingReadPairReader> for BAMStreamingReadPairReaderFactory {
fn new_from_path(&self, fname: &PathBuf) -> anyhow::Result<BAMStreamingReadPairReader> { BAMStreamingReadPairReader::new(fname)
}
}