noodles_sam/record/
cigar.rs1use std::{fmt, io, iter};
2
3use crate::{alignment::record::cigar::Op, io::reader::record_buf::cigar::op};
4
5#[derive(Eq, PartialEq)]
7pub struct Cigar<'a>(&'a [u8]);
8
9impl<'a> Cigar<'a> {
10 pub fn new(src: &'a [u8]) -> Self {
19 Self(src)
20 }
21
22 pub fn is_empty(&self) -> bool {
36 self.0.is_empty()
37 }
38
39 pub fn iter(&self) -> impl Iterator<Item = Result<Op, op::ParseError>> + '_ {
60 use crate::io::reader::record_buf::cigar::op::parse_op;
61
62 let mut src = self.0;
63
64 iter::from_fn(move || {
65 if src.is_empty() {
66 None
67 } else {
68 Some(parse_op(&mut src))
69 }
70 })
71 }
72}
73
74impl fmt::Debug for Cigar<'_> {
75 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
76 f.debug_list().entries(self.iter()).finish()
77 }
78}
79
80impl crate::alignment::record::Cigar for Cigar<'_> {
81 fn is_empty(&self) -> bool {
82 self.is_empty()
83 }
84
85 fn len(&self) -> usize {
86 self.as_ref()
87 .iter()
88 .filter(|&b| {
89 matches!(
90 b,
91 b'M' | b'I' | b'D' | b'N' | b'S' | b'H' | b'P' | b'=' | b'X'
92 )
93 })
94 .count()
95 }
96
97 fn iter(&self) -> Box<dyn Iterator<Item = io::Result<Op>> + '_> {
98 Box::new(self.iter().map(|result| {
99 result
100 .map(|op| Op::new(op.kind(), op.len()))
101 .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
102 }))
103 }
104}
105
106impl AsRef<[u8]> for Cigar<'_> {
107 fn as_ref(&self) -> &[u8] {
108 self.0
109 }
110}
111
112impl<'a> TryFrom<Cigar<'a>> for crate::alignment::record_buf::Cigar {
113 type Error = io::Error;
114
115 fn try_from(Cigar(src): Cigar<'a>) -> Result<Self, Self::Error> {
116 use crate::io::reader::record_buf::parse_cigar;
117
118 let mut cigar = Self::default();
119
120 if !src.is_empty() {
121 parse_cigar(src, &mut cigar)
122 .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
123 }
124
125 Ok(cigar)
126 }
127}