d4_hts/alignment/
cigar_ext.rs1use 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}