pub mod op;
#[doc(hidden)]
pub mod iter;
use std::io;
pub use self::op::Op;
pub trait Cigar {
fn is_empty(&self) -> bool;
fn len(&self) -> usize;
fn iter(&self) -> Box<dyn Iterator<Item = io::Result<Op>> + '_>;
fn alignment_span(&self) -> io::Result<usize> {
let mut span = 0;
for result in self.iter() {
let op = result?;
if op.kind().consumes_reference() {
span += op.len();
}
}
Ok(span)
}
fn read_length(&self) -> io::Result<usize> {
let mut length = 0;
for result in self.iter() {
let op = result?;
if op.kind().consumes_read() {
length += op.len();
}
}
Ok(length)
}
}
impl<'a> IntoIterator for &'a dyn Cigar {
type Item = io::Result<Op>;
type IntoIter = Box<dyn Iterator<Item = Self::Item> + 'a>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl Cigar for Box<dyn Cigar + '_> {
fn is_empty(&self) -> bool {
(**self).is_empty()
}
fn len(&self) -> usize {
(**self).len()
}
fn iter(&self) -> Box<dyn Iterator<Item = io::Result<Op>> + '_> {
(**self).iter()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::alignment::record::cigar::op::Kind;
struct T(Vec<Op>);
impl Cigar for T {
fn is_empty(&self) -> bool {
self.0.is_empty()
}
fn len(&self) -> usize {
self.0.len()
}
fn iter(&self) -> Box<dyn Iterator<Item = io::Result<Op>> + '_> {
Box::new(self.0.iter().copied().map(Ok))
}
}
#[test]
fn test_into_iter() -> io::Result<()> {
let cigar: &dyn Cigar = &T(vec![Op::new(Kind::Match, 4)]);
assert_eq!(
cigar.into_iter().collect::<io::Result<Vec<_>>>()?,
[Op::new(Kind::Match, 4)]
);
Ok(())
}
#[test]
fn test_alignment_span() -> io::Result<()> {
let cigar: &dyn Cigar = &T(vec![
Op::new(Kind::Match, 36),
Op::new(Kind::Deletion, 4),
Op::new(Kind::SoftClip, 8),
]);
assert_eq!(cigar.alignment_span()?, 40);
Ok(())
}
#[test]
fn test_read_length() -> io::Result<()> {
let cigar: &dyn Cigar = &T(vec![
Op::new(Kind::Match, 36),
Op::new(Kind::Deletion, 4),
Op::new(Kind::SoftClip, 8),
]);
assert_eq!(cigar.read_length()?, 44);
Ok(())
}
}