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
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 }
}
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 {
matches!(
self.op,
CigarOps::Match | CigarOps::Insert | CigarOps::Soft | CigarOps::Equal | CigarOps::Diff
)
}
pub fn in_reference(&self) -> bool {
matches!(
self.op,
CigarOps::Match | CigarOps::Delete | CigarOps::Skip | CigarOps::Equal | CigarOps::Diff
)
}
}
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,
}
}
}