use std::io::{self, Write};
use crate::{
alignment::record::{
cigar::{op::Kind, Op},
Cigar,
},
io::writer::num,
};
pub fn write_cigar<W, C>(writer: &mut W, cigar: &C) -> io::Result<()>
where
W: Write,
C: Cigar,
{
use super::MISSING;
if cigar.is_empty() {
writer.write_all(&[MISSING])?;
} else {
for result in cigar.iter() {
let op = result?;
write_op(writer, op)?;
}
}
Ok(())
}
fn write_op<W>(writer: &mut W, op: Op) -> io::Result<()>
where
W: Write,
{
num::write_usize(writer, op.len())?;
write_kind(writer, op.kind())?;
Ok(())
}
fn write_kind<W>(writer: &mut W, kind: Kind) -> io::Result<()>
where
W: Write,
{
let c = match kind {
Kind::Match => b'M',
Kind::Insertion => b'I',
Kind::Deletion => b'D',
Kind::Skip => b'N',
Kind::SoftClip => b'S',
Kind::HardClip => b'H',
Kind::Pad => b'P',
Kind::SequenceMatch => b'=',
Kind::SequenceMismatch => b'X',
};
writer.write_all(&[c])
}
#[cfg(test)]
mod tests {
use super::*;
use crate::alignment::record_buf::Cigar as CigarBuf;
#[test]
fn test_write_cigar() -> io::Result<()> {
fn t(buf: &mut Vec<u8>, cigar: &CigarBuf, expected: &[u8]) -> io::Result<()> {
buf.clear();
write_cigar(buf, cigar)?;
assert_eq!(buf, expected);
Ok(())
}
let mut buf = Vec::new();
let cigar = CigarBuf::default();
t(&mut buf, &cigar, b"*")?;
let cigar = [Op::new(Kind::Match, 4)].into_iter().collect();
t(&mut buf, &cigar, b"4M")?;
let cigar: CigarBuf = [Op::new(Kind::Match, 4), Op::new(Kind::HardClip, 2)]
.into_iter()
.collect();
t(&mut buf, &cigar, b"4M2H")?;
Ok(())
}
#[test]
fn test_write_op() -> io::Result<()> {
let mut buf = Vec::new();
buf.clear();
write_op(&mut buf, Op::new(Kind::Match, 1))?;
assert_eq!(buf, b"1M");
buf.clear();
write_op(&mut buf, Op::new(Kind::Match, 1 << 28))?;
assert_eq!(buf, b"268435456M");
Ok(())
}
#[test]
fn test_write_kind() -> io::Result<()> {
fn t(buf: &mut Vec<u8>, kind: Kind, expected: &[u8]) -> io::Result<()> {
buf.clear();
write_kind(buf, kind)?;
assert_eq!(buf, expected);
Ok(())
}
let mut buf = Vec::new();
t(&mut buf, Kind::Match, b"M")?;
t(&mut buf, Kind::Insertion, b"I")?;
t(&mut buf, Kind::Deletion, b"D")?;
t(&mut buf, Kind::Skip, b"N")?;
t(&mut buf, Kind::SoftClip, b"S")?;
t(&mut buf, Kind::HardClip, b"H")?;
t(&mut buf, Kind::Pad, b"P")?;
t(&mut buf, Kind::SequenceMatch, b"=")?;
t(&mut buf, Kind::SequenceMismatch, b"X")?;
Ok(())
}
}