noodles_bam/record/
cigar.rs1use std::{fmt, io, mem};
2
3use noodles_sam::{self as sam, alignment::record::cigar::Op};
4
5const CHUNK_SIZE: usize = mem::size_of::<u32>();
6
7#[derive(Eq, PartialEq)]
9pub struct Cigar<'a>(&'a [u8]);
10
11impl<'a> Cigar<'a> {
12 pub(super) fn new(src: &'a [u8]) -> Self {
13 Self(src)
14 }
15
16 pub fn is_empty(&self) -> bool {
18 self.0.is_empty()
19 }
20
21 pub fn len(&self) -> usize {
25 self.0.len() / CHUNK_SIZE
26 }
27
28 pub fn iter(&self) -> impl Iterator<Item = io::Result<Op>> + '_ {
30 use crate::record::codec::decoder::cigar::decode_op;
31
32 self.0.chunks(CHUNK_SIZE).map(|chunk| {
33 let buf = chunk
34 .try_into()
35 .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
36 let n = u32::from_le_bytes(buf);
37 decode_op(n).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
38 })
39 }
40}
41
42impl sam::alignment::record::Cigar for Cigar<'_> {
43 fn is_empty(&self) -> bool {
44 self.is_empty()
45 }
46
47 fn len(&self) -> usize {
48 self.len()
49 }
50
51 fn iter(&self) -> Box<dyn Iterator<Item = io::Result<Op>> + '_> {
52 Box::new(self.iter())
53 }
54}
55
56impl AsRef<[u8]> for Cigar<'_> {
57 fn as_ref(&self) -> &[u8] {
58 self.0
59 }
60}
61
62impl fmt::Debug for Cigar<'_> {
63 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
64 f.debug_list().entries(self.iter()).finish()
65 }
66}
67
68impl<'a> TryFrom<Cigar<'a>> for sam::alignment::record_buf::Cigar {
69 type Error = io::Error;
70
71 fn try_from(bam_cigar: Cigar<'a>) -> Result<Self, Self::Error> {
72 bam_cigar.iter().collect()
73 }
74}
75
76#[cfg(test)]
77mod tests {
78 use super::*;
79
80 #[test]
81 fn test_iter() -> io::Result<()> {
82 use sam::alignment::record::cigar::op::Kind;
83
84 let src = &[][..];
85 let cigar = Cigar::new(src);
86 assert!(cigar.iter().next().is_none());
87
88 let src = &[0x40, 0x00, 0x00, 0x00][..];
89 let cigar = Cigar::new(src);
90 let actual: Vec<_> = cigar.iter().collect::<io::Result<_>>()?;
91 let expected = [Op::new(Kind::Match, 4)];
92 assert_eq!(actual, expected);
93
94 let src = &[0x40, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00][..];
95 let cigar = Cigar::new(src);
96 let actual: Vec<_> = cigar.iter().collect::<io::Result<_>>()?;
97 let expected = [Op::new(Kind::Match, 4), Op::new(Kind::HardClip, 2)];
98 assert_eq!(actual, expected);
99
100 Ok(())
101 }
102}