use std::io::{self, BufRead};
use flate2::read::GzDecoder;
use seq_io::fastq::Reader as FastqReader;
use crate::fileformat::shard::CellID;
use crate::fileformat::shard::ReadPair;
use crate::barcode::Chemistry;
use crate::barcode::CombinatorialBarcode;
#[derive(Clone)]
pub struct TenxChemistry {
barcode: CombinatorialBarcode
}
impl Chemistry for TenxChemistry {
fn prepare(
&mut self,
_fastq_file_r1: &mut FastqReader<Box<dyn std::io::Read>>,
fastq_file_r2: &mut FastqReader<Box<dyn std::io::Read>>
) -> anyhow::Result<()> {
self.barcode = read_barcodes_10x(include_bytes!("3M-february-2018.txt.gz"));
self.barcode.find_probable_barcode_boundaries(fastq_file_r2, 10000).expect("Failed to detect barcode setup from reads");
Ok(())
}
fn detect_barcode_and_trim(
&mut self,
r1_seq: &[u8],
r1_qual: &[u8],
r2_seq: &[u8],
r2_qual: &[u8]
) -> (bool, CellID, ReadPair) {
let total_distance_cutoff = 1;
let (isok, bc) = self.barcode.detect_barcode(
r2_seq,
false,
total_distance_cutoff
);
if isok {
let r1_from=0;
let r1_to=r1_seq.len();
let r2_from = 8+4+8+4+8+4+8;
let r2_to = r2_seq.len();
(true, bc, ReadPair{
r1: r1_seq[r1_from..r1_to].to_vec(),
r2: r2_seq[r2_from..r2_to].to_vec(),
q1: r1_qual[r1_from..r1_to].to_vec(),
q2: r2_qual[r2_from..r2_to].to_vec(),
umi: vec![].to_vec()})
} else {
(false, "".to_string(), ReadPair{r1: r1_seq.to_vec(), r2: r2_seq.to_vec(), q1: r1_qual.to_vec(), q2: r2_qual.to_vec(), umi: vec![].to_vec()})
}
}
}
impl TenxChemistry {
pub fn new() -> TenxChemistry {
TenxChemistry {
barcode: CombinatorialBarcode::new()
}
}
}
fn read_barcodes_10x(bc_bytes: &[u8]) -> CombinatorialBarcode {
let mut cb: CombinatorialBarcode = CombinatorialBarcode::new();
let gz = GzDecoder::new(&bc_bytes[..]);
let lines = io::BufReader::new(gz).lines();
let poolname = "p";
for bc in lines.flatten() {
cb.add_bc(
bc.as_str(), poolname, bc.as_str(), );
}
if cb.num_pools()==0 {
println!("Warning: empty barcodes file");
}
cb
}