use bstr::BString;
use indexmap::map::IndexMap;
use noodles_sam::{
self as sam,
alignment::io::Write,
header::record::value::{map::ReferenceSequence, Map},
};
use crate::PseudoAln;
type E = Box<dyn std::error::Error>;
#[allow(unreachable_code, unused_variables)]
pub fn format_sam_line<W: std::io::Write>(
aln: &PseudoAln,
header: &sam::Header,
conn: &mut W,
) -> Result<(), E> {
todo!("Print PseudoAln in SAM format");
if aln.query_name.is_none() {
return Err(Box::new(crate::errors::SamPrinterError{}))
}
if aln.ones.is_none() || (aln.ones.is_none() && aln.ones.as_ref().unwrap().is_empty()) {
return Err(Box::new(crate::errors::SamPrinterError{}))
}
let mut writer = noodles_sam::io::Writer::new(Vec::new());
for target_id in aln.ones.as_ref().unwrap() {
let record = sam::alignment::RecordBuf::builder()
.set_name(aln.query_name.clone().unwrap())
.set_reference_sequence_id(*target_id as usize)
.build();
writer.write_alignment_record(header, &record)?;
}
conn.write_all(writer.get_ref())?;
Ok(())
}
pub fn build_sam_header(
targets: &[Vec<u8>],
) -> Result<sam::Header, E> {
let refs = targets.iter().map(|target_name| {
(
BString::from(target_name.clone()),
Map::<ReferenceSequence>::new(std::num::NonZeroUsize::try_from(1).unwrap()),
)
}).collect::<IndexMap<BString, Map<ReferenceSequence>>>();
Ok(
sam::Header::builder()
.set_header(Default::default())
.set_reference_sequences(refs)
.build()
)
}
pub fn format_sam_header<W: std::io::Write>(
header: &sam::Header,
conn: &mut W,
) -> Result<(), E> {
let mut writer = noodles_sam::io::Writer::new(Vec::new());
writer.write_header(header)?;
conn.write_all(writer.get_ref())?;
Ok(())
}
#[cfg(test)]
mod tests {
#[test]
#[should_panic(expected = "not yet implemented")]
fn format_sam_line_aligned() {
use crate::headers::file::FileFlags;
use super::build_sam_header;
use super::format_sam_line;
use crate::PseudoAln;
let fflags = FileFlags { target_names: vec!["chr.fasta".as_bytes().to_vec(), "plasmid.fasta".as_bytes().to_vec()], query_name: "test.fastq".as_bytes().to_vec() };
let mut expected: Vec<u8> = b"@HD\tVN:1.6\n".to_vec();
expected.append(&mut b"@SQ\tSN:chr.fasta\tLN:1\n".to_vec());
expected.append(&mut b"@SQ\tSN:plasmid.fasta\tLN:1\n".to_vec());
expected.append(&mut b"@RG\tID:test.fastq\n".to_vec());
let header = build_sam_header(&fflags.target_names).unwrap();
let data = PseudoAln{ones_names: Some(vec!["OZ038621.1".as_bytes().to_vec()]), query_id: None, ones: Some(vec![1]), query_name: Some("ERR4035126.1".as_bytes().to_vec()) };
let expected: Vec<u8> =b"ERR4035126.1\t4\tplasmid.fasta\t0\t255\t*\t*\t0\t0\t*\t*\n".to_vec();
let mut got: Vec<u8> = Vec::new();
format_sam_line(&data, &header, &mut got).unwrap();
assert_eq!(got.iter().map(|x| *x as char).collect::<String>(), expected.iter().map(|x| *x as char).collect::<String>())
}
#[test]
fn build_sam_header() {
use crate::headers::file::FileFlags;
use super::build_sam_header;
use super::format_sam_header;
let fflags = FileFlags { target_names: vec!["chr.fasta".as_bytes().to_vec(), "plasmid.fasta".as_bytes().to_vec()], query_name: "test.fastq".as_bytes().to_vec() };
let mut expected: Vec<u8> = b"@HD\tVN:1.6\n".to_vec();
expected.append(&mut b"@SQ\tSN:chr.fasta\tLN:1\n".to_vec());
expected.append(&mut b"@SQ\tSN:plasmid.fasta\tLN:1\n".to_vec());
let header = build_sam_header(&fflags.target_names).unwrap();
let mut got: Vec<u8> = Vec::new();
format_sam_header(&header, &mut got).unwrap();
assert_eq!(got, expected)
}
}