noodles_sam/alignment/record/
cigar.rs1pub mod op;
4
5#[doc(hidden)]
6pub mod iter;
7
8use std::io;
9
10pub use self::op::Op;
11
12pub trait Cigar {
14 fn is_empty(&self) -> bool;
16
17 fn len(&self) -> usize;
19
20 fn iter(&self) -> Box<dyn Iterator<Item = io::Result<Op>> + '_>;
22
23 fn alignment_span(&self) -> io::Result<usize> {
25 let mut span = 0;
26
27 for result in self.iter() {
28 let op = result?;
29
30 if op.kind().consumes_reference() {
31 span += op.len();
32 }
33 }
34
35 Ok(span)
36 }
37
38 fn read_length(&self) -> io::Result<usize> {
40 let mut length = 0;
41
42 for result in self.iter() {
43 let op = result?;
44
45 if op.kind().consumes_read() {
46 length += op.len();
47 }
48 }
49
50 Ok(length)
51 }
52}
53
54impl<'a> IntoIterator for &'a dyn Cigar {
55 type Item = io::Result<Op>;
56 type IntoIter = Box<dyn Iterator<Item = Self::Item> + 'a>;
57
58 fn into_iter(self) -> Self::IntoIter {
59 self.iter()
60 }
61}
62
63impl Cigar for Box<dyn Cigar + '_> {
64 fn is_empty(&self) -> bool {
65 (**self).is_empty()
66 }
67
68 fn len(&self) -> usize {
69 (**self).len()
70 }
71
72 fn iter(&self) -> Box<dyn Iterator<Item = io::Result<Op>> + '_> {
73 (**self).iter()
74 }
75}
76
77#[cfg(test)]
78mod tests {
79 use super::*;
80 use crate::alignment::record::cigar::op::Kind;
81
82 struct T(Vec<Op>);
83
84 impl Cigar for T {
85 fn is_empty(&self) -> bool {
86 self.0.is_empty()
87 }
88
89 fn len(&self) -> usize {
90 self.0.len()
91 }
92
93 fn iter(&self) -> Box<dyn Iterator<Item = io::Result<Op>> + '_> {
94 Box::new(self.0.iter().copied().map(Ok))
95 }
96 }
97
98 #[test]
99 fn test_into_iter() -> io::Result<()> {
100 let cigar: &dyn Cigar = &T(vec![Op::new(Kind::Match, 4)]);
101
102 assert_eq!(
103 cigar.into_iter().collect::<io::Result<Vec<_>>>()?,
104 [Op::new(Kind::Match, 4)]
105 );
106
107 Ok(())
108 }
109
110 #[test]
111 fn test_alignment_span() -> io::Result<()> {
112 let cigar: &dyn Cigar = &T(vec![
113 Op::new(Kind::Match, 36),
114 Op::new(Kind::Deletion, 4),
115 Op::new(Kind::SoftClip, 8),
116 ]);
117
118 assert_eq!(cigar.alignment_span()?, 40);
119
120 Ok(())
121 }
122
123 #[test]
124 fn test_read_length() -> io::Result<()> {
125 let cigar: &dyn Cigar = &T(vec![
126 Op::new(Kind::Match, 36),
127 Op::new(Kind::Deletion, 4),
128 Op::new(Kind::SoftClip, 8),
129 ]);
130
131 assert_eq!(cigar.read_length()?, 44);
132
133 Ok(())
134 }
135}