1pub fn misd(old_cigar: &str, seq_length: i32) -> [i32; 4] {
21 let mut cigar_ite = [0, 0, 0, 0];
22
23 if old_cigar == "*" {
25 cigar_ite[3] = -1;
26 return cigar_ite;
27 }
28
29 let mut counts = Vec::with_capacity(4);
31 let mut ops = Vec::with_capacity(4);
32
33 let mut current_val = 0;
34 for c in old_cigar.chars() {
35 if c.is_digit(10) {
36 current_val = current_val * 10 + c.to_digit(10).unwrap() as i32;
37 } else {
38 if matches!(c, 'M' | 'I' | 'D' | 'N' | 'S' | 'H' | 'P' | '=' | 'X') {
40 let op = if c == 'H' { 'S' } else { c };
41 counts.push(current_val);
42 ops.push(op);
43 current_val = 0;
44 } else {
45 cigar_ite[3] = -2;
47 return cigar_ite;
48 }
49 }
50 }
51
52 if ops.is_empty() {
54 cigar_ite[3] = -2;
55 return cigar_ite;
56 }
57
58 if ops.len() == 1 {
59 if ops[0] == 'M' {
60 cigar_ite[3] = seq_length;
61 } else {
62 cigar_ite[3] = -1;
63 }
64 } else if ops.len() == 2 {
65 if ops[0] == 'M' && ops[1] == 'S' {
66 cigar_ite[0] = 1;
67 cigar_ite[1] = counts[0];
68 cigar_ite[2] = counts[0] - 1;
69 cigar_ite[3] = counts[0];
70 } else if ops[0] == 'S' && ops[1] == 'M' {
71 cigar_ite[0] = -1;
72 cigar_ite[1] = counts[0];
73 cigar_ite[2] = 0;
74 cigar_ite[3] = counts[1];
75 } else {
76 cigar_ite[3] = -2;
77 }
78 } else if ops.len() == 3 {
79 if ops[0] == 'S' && ops[1] == 'M' && ops[2] == 'S' {
80 cigar_ite[0] = 10;
81 cigar_ite[1] = counts[0];
82 cigar_ite[2] = counts[2];
83 cigar_ite[3] = counts[1];
84 } else if ops[0] == 'M' && ops[1] == 'D' && ops[2] == 'M' {
85 cigar_ite[3] = seq_length + counts[1];
86 } else if ops[0] == 'M' && ops[1] == 'I' && ops[2] == 'M' {
87 cigar_ite[3] = seq_length - counts[1];
88 } else {
89 cigar_ite[3] = -2;
90 }
91 } else if ops[0] == 'M' && *ops.last().unwrap() == 'S' {
92 let (mut m_sum, mut d_sum) = (0, 0);
93 for i in 0..ops.len() {
94 if ops[i] == 'M' {
95 m_sum += counts[i];
96 } else if ops[i] == 'D' {
97 d_sum += counts[i];
98 }
99 }
100 cigar_ite[0] = 1;
101 cigar_ite[1] = seq_length - counts.last().unwrap();
102 cigar_ite[2] = m_sum + d_sum - 1;
103 cigar_ite[3] = m_sum + d_sum;
104 } else if ops[0] == 'S' && *ops.last().unwrap() == 'M' {
105 let (mut m_sum, mut d_sum) = (0, 0);
106 for i in 1..ops.len() {
107 if ops[i] == 'M' {
108 m_sum += counts[i];
109 } else if ops[i] == 'D' {
110 d_sum += counts[i];
111 }
112 }
113 cigar_ite[0] = -1;
114 cigar_ite[1] = counts[0];
115 cigar_ite[2] = 0;
116 cigar_ite[3] = m_sum + d_sum;
117 } else if ops[0] == 'M' && *ops.last().unwrap() == 'M' {
118 let (mut m_sum, mut d_sum) = (0, 0);
119 for i in 0..ops.len() {
120 if ops[i] == 'M' {
121 m_sum += counts[i];
122 } else if ops[i] == 'D' {
123 d_sum += counts[i];
124 }
125 }
126 cigar_ite[3] = m_sum + d_sum;
127 } else if ops[0] == 'S' && *ops.last().unwrap() == 'S' {
128 let (mut m_sum, mut d_sum) = (0, 0);
129 for i in 1..ops.len() - 1 {
130 if ops[i] == 'M' {
131 m_sum += counts[i];
132 } else if ops[i] == 'D' {
133 d_sum += counts[i];
134 }
135 }
136 cigar_ite[0] = 10;
137 cigar_ite[1] = counts[0];
138 cigar_ite[2] = *counts.last().unwrap();
139 cigar_ite[3] = m_sum + d_sum;
140 } else {
141 cigar_ite[3] = -2;
142 }
143
144 cigar_ite
145}
146
147#[cfg(test)]
148mod tests {
149 use super::*;
150
151 #[test]
152 fn test_misd_match() {
153 let res = misd("100M", 100);
154 assert_eq!(res, [0, 0, 0, 100]);
155 }
156
157 #[test]
158 fn test_misd_invalid() {
159 let res = misd("*", 100);
160 assert_eq!(res[3], -1);
161 }
162
163 #[test]
164 fn test_misd_soft_clip_start() {
165 let res = misd("20S80M", 100);
166 assert_eq!(res, [-1, 20, 0, 80]);
167 }
168
169 #[test]
170 fn test_misd_soft_clip_end() {
171 let res = misd("80M20S", 100);
172 assert_eq!(res, [1, 80, 79, 80]);
173 }
174
175 #[test]
176 fn test_misd_insertion() {
177 let res = misd("40M2I58M", 100);
178 assert_eq!(res, [0, 0, 0, 98]);
179 }
180
181 #[test]
182 fn test_misd_deletion() {
183 let res = misd("40M2D58M", 98);
184 assert_eq!(res, [0, 0, 0, 100]);
185 }
186
187 #[test]
188 fn test_misd_complex() {
189 let res = misd("10S30M2I40M20S", 102);
190 assert_eq!(res, [10, 10, 20, 70]);
191 }
192}