1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
use super::htslib::*; use super::Alignment; #[derive(Debug)] pub enum CigarOps { Match, Insert, Delete, Skip, Soft, Hard, Pad, Equal, Diff, Back, } #[derive(Debug)] pub struct Cigar { pub op: CigarOps, pub len: u32, } impl std::fmt::Display for Cigar { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!( f, "{}{}", self.len, match self.op { CigarOps::Match => "M", CigarOps::Insert => "I", CigarOps::Delete => "D", CigarOps::Skip => "N", CigarOps::Soft => "S", CigarOps::Hard => "H", CigarOps::Pad => "P", CigarOps::Equal => "=", CigarOps::Diff => "X", CigarOps::Back => "B", }, ) } } impl Cigar { fn new(ops: CigarOps, len: u32) -> Cigar { Cigar { op: ops, len: len } } fn from_alignment(al: &Alignment, idx: usize) -> Option<Cigar> { if idx >= (al.hts_obj().core.n_cigar as usize) { return None; } let cigar_num: u32 = unsafe { *(al.hts_obj() .data .offset(al.hts_obj().core.l_qname as isize + (idx * 4) as isize) as *const u32) }; let cigar_op = cigar_num & BAM_CIGAR_MASK; let cigar_len = cigar_num >> BAM_CIGAR_SHIFT; match cigar_op { BAM_CMATCH => Some(Cigar::new(CigarOps::Match, cigar_len)), BAM_CINS => Some(Cigar::new(CigarOps::Insert, cigar_len)), BAM_CDEL => Some(Cigar::new(CigarOps::Delete, cigar_len)), BAM_CREF_SKIP => Some(Cigar::new(CigarOps::Skip, cigar_len)), BAM_CSOFT_CLIP => Some(Cigar::new(CigarOps::Soft, cigar_len)), BAM_CHARD_CLIP => Some(Cigar::new(CigarOps::Hard, cigar_len)), BAM_CPAD => Some(Cigar::new(CigarOps::Pad, cigar_len)), BAM_CEQUAL => Some(Cigar::new(CigarOps::Equal, cigar_len)), BAM_CDIFF => Some(Cigar::new(CigarOps::Diff, cigar_len)), BAM_CBACK => Some(Cigar::new(CigarOps::Back, cigar_len)), _ => None, } } pub fn in_alignment(&self) -> bool { match self.op { CigarOps::Match | CigarOps::Insert | CigarOps::Soft | CigarOps::Equal | CigarOps::Diff => true, _ => false, } } pub fn in_reference(&self) -> bool { match self.op { CigarOps::Match | CigarOps::Delete | CigarOps::Skip | CigarOps::Equal | CigarOps::Diff => true, _ => false, } } } pub struct CigarIter<'a> { alignment: &'a Alignment<'a>, offset: usize, } impl<'a> Iterator for CigarIter<'a> { type Item = Cigar; fn next(&mut self) -> Option<Cigar> { if let Some(ret) = Cigar::from_alignment(self.alignment, self.offset) { self.offset += 1; return Some(ret); } None } } impl<'a> Alignment<'a> { pub fn cigar(&self) -> CigarIter { CigarIter { alignment: self, offset: 0, } } }