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
//! Alignment record CIGAR operation kind.

/// An alignment record CIGAR operation kind.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Kind {
    /// An alignment match (`M`).
    Match,
    /// An insertion into the reference (`I`).
    Insertion,
    /// A deletion from the reference (`D`).
    Deletion,
    /// A skipped region from the reference (`N`).
    Skip,
    /// A soft clip (`S`).
    SoftClip,
    /// A hard clip (`H`).
    HardClip,
    /// Padding (`P`).
    Pad,
    /// A sequence match (`=`).
    SequenceMatch,
    /// A sequence mismatch (`X`).
    SequenceMismatch,
}

impl Kind {
    /// Returns whether the operation kind causes the alignment to consume the read.
    ///
    /// # Examples
    ///
    /// ```
    /// use noodles_sam::alignment::record::cigar::op::Kind;
    /// assert!(Kind::Match.consumes_read());
    /// assert!(Kind::Insertion.consumes_read());
    /// assert!(!Kind::Deletion.consumes_read());
    /// ```
    pub fn consumes_read(&self) -> bool {
        matches!(
            self,
            Self::Match
                | Self::Insertion
                | Self::SoftClip
                | Self::SequenceMatch
                | Self::SequenceMismatch
        )
    }

    /// Returns whether the operation kind causes the alignment to consume the reference.
    ///
    /// # Examples
    ///
    /// ```
    /// use noodles_sam::alignment::record::cigar::op::Kind;
    /// assert!(Kind::Match.consumes_reference());
    /// assert!(!Kind::Insertion.consumes_reference());
    /// assert!(Kind::Deletion.consumes_reference());
    /// ```
    pub fn consumes_reference(&self) -> bool {
        matches!(
            self,
            Self::Match
                | Self::Deletion
                | Self::Skip
                | Self::SequenceMatch
                | Self::SequenceMismatch
        )
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_consumes_read() {
        assert!(Kind::Match.consumes_read());
        assert!(Kind::Insertion.consumes_read());
        assert!(!Kind::Deletion.consumes_read());
        assert!(!Kind::Skip.consumes_read());
        assert!(Kind::SoftClip.consumes_read());
        assert!(!Kind::HardClip.consumes_read());
        assert!(!Kind::Pad.consumes_read());
        assert!(Kind::SequenceMatch.consumes_read());
        assert!(Kind::SequenceMismatch.consumes_read());
    }

    #[test]
    fn test_consumes_reference() {
        assert!(Kind::Match.consumes_reference());
        assert!(!Kind::Insertion.consumes_reference());
        assert!(Kind::Deletion.consumes_reference());
        assert!(Kind::Skip.consumes_reference());
        assert!(!Kind::SoftClip.consumes_reference());
        assert!(!Kind::HardClip.consumes_reference());
        assert!(!Kind::Pad.consumes_reference());
        assert!(Kind::SequenceMatch.consumes_reference());
        assert!(Kind::SequenceMismatch.consumes_reference());
    }
}