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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
//! CRAM record feature.

pub mod code;

pub use self::code::Code;

/// A CRAM record feature.
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Feature {
    /// A stretch of bases (position, bases).
    Bases(i32, Vec<u8>),
    /// A stretch of quality scores (position, quality scores).
    Scores(i32, Vec<u8>),
    /// A base-quality score pair (position, base, quality score).
    ReadBase(i32, u8, u8),
    /// A base substitution (position, code).
    Substitution(i32, u8),
    /// Inserted bases (position, bases).
    Insertion(i32, Vec<u8>),
    /// A number of deleted bases (position, length).
    Deletion(i32, i32),
    /// A single inserted base (position, base).
    InsertBase(i32, u8),
    /// A single quality score (position, score).
    QualityScore(i32, u8),
    /// A number of skipped bases (position, length).
    ReferenceSkip(i32, i32),
    /// Soft clipped bases (position, bases).
    SoftClip(i32, Vec<u8>),
    /// A number of padded bases (position, length).
    Padding(i32, i32),
    /// A number of hard clipped bases (position, length).
    HardClip(i32, i32),
}

impl Feature {
    /// Returns the feature code.
    ///
    /// # Examples
    ///
    /// ```
    /// use noodles_cram::record::{feature::Code, Feature};
    /// let feature = Feature::InsertBase(8, b'A');
    /// assert_eq!(feature.code(), Code::InsertBase);
    /// ```
    pub fn code(&self) -> Code {
        match self {
            Self::Bases(..) => Code::Bases,
            Self::Scores(..) => Code::Scores,
            Self::ReadBase(..) => Code::ReadBase,
            Self::Substitution(..) => Code::Substitution,
            Self::Insertion(..) => Code::Insertion,
            Self::Deletion(..) => Code::Deletion,
            Self::InsertBase(..) => Code::InsertBase,
            Self::QualityScore(..) => Code::QualityScore,
            Self::ReferenceSkip(..) => Code::ReferenceSkip,
            Self::SoftClip(..) => Code::SoftClip,
            Self::Padding(..) => Code::Padding,
            Self::HardClip(..) => Code::HardClip,
        }
    }

    /// Returns the feature position.
    ///
    /// # Examples
    ///
    /// ```
    /// use noodles_cram::record::Feature;
    /// let feature = Feature::InsertBase(8, b'A');
    /// assert_eq!(feature.position(), 8);
    /// ```
    pub fn position(&self) -> i32 {
        match self {
            Self::Bases(pos, _) => *pos,
            Self::Scores(pos, _) => *pos,
            Self::ReadBase(pos, _, _) => *pos,
            Self::Substitution(pos, _) => *pos,
            Self::Insertion(pos, _) => *pos,
            Self::Deletion(pos, _) => *pos,
            Self::InsertBase(pos, _) => *pos,
            Self::QualityScore(pos, _) => *pos,
            Self::ReferenceSkip(pos, _) => *pos,
            Self::SoftClip(pos, _) => *pos,
            Self::Padding(pos, _) => *pos,
            Self::HardClip(pos, _) => *pos,
        }
    }
}

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

    #[test]
    fn test_code() {
        assert_eq!(Feature::Bases(1, Vec::new()).code(), Code::Bases);
        assert_eq!(Feature::Scores(1, Vec::new()).code(), Code::Scores);
        assert_eq!(Feature::ReadBase(1, 0, 0).code(), Code::ReadBase);
        assert_eq!(Feature::Substitution(1, 0).code(), Code::Substitution);
        assert_eq!(Feature::Insertion(1, Vec::new()).code(), Code::Insertion);
        assert_eq!(Feature::Deletion(1, 0).code(), Code::Deletion);
        assert_eq!(Feature::InsertBase(1, 0).code(), Code::InsertBase);
        assert_eq!(Feature::QualityScore(1, 0).code(), Code::QualityScore);
        assert_eq!(Feature::ReferenceSkip(1, 0).code(), Code::ReferenceSkip);
        assert_eq!(Feature::SoftClip(1, Vec::new()).code(), Code::SoftClip);
        assert_eq!(Feature::Padding(1, 0).code(), Code::Padding);
        assert_eq!(Feature::HardClip(1, 0).code(), Code::HardClip);
    }

    #[test]
    fn test_position() {
        assert_eq!(Feature::Bases(1, Vec::new()).position(), 1);
        assert_eq!(Feature::Scores(2, Vec::new()).position(), 2);
        assert_eq!(Feature::ReadBase(3, 0, 0).position(), 3);
        assert_eq!(Feature::Substitution(4, 0).position(), 4);
        assert_eq!(Feature::Insertion(5, Vec::new()).position(), 5);
        assert_eq!(Feature::Deletion(6, 0).position(), 6);
        assert_eq!(Feature::InsertBase(7, 0).position(), 7);
        assert_eq!(Feature::QualityScore(8, 0).position(), 8);
        assert_eq!(Feature::ReferenceSkip(9, 0).position(), 9);
        assert_eq!(Feature::SoftClip(10, Vec::new()).position(), 10);
        assert_eq!(Feature::Padding(11, 0).position(), 11);
        assert_eq!(Feature::HardClip(12, 0).position(), 12);
    }
}