d4_hts/alignment/
cigar_ext.rs

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