read_structure/
segment_type.rs

1//! Segment Types
2//!
3//! Type [`SegmentType`] represents the types of segments that can show
4//! up in a read structure ([`crate::read_structure::ReadStructure`]: trait.ReadStructure).
5
6use std::{convert::TryFrom, mem};
7
8use strum::IntoEnumIterator;
9use strum_macros::EnumIter;
10
11use crate::ReadStructureError;
12
13/// The `SegmentType` type. See [the module level documentation](self) for more.
14#[non_exhaustive]
15#[derive(Debug, Copy, Clone, EnumIter, PartialEq, Eq, Hash, PartialOrd, Ord)]
16#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
17#[repr(u8)]
18pub enum SegmentType {
19    /// Template: the bases in the segment are reads of template (e.g. genomic dna, rna, etc.)
20    Template = b'T',
21    /// Sample Barcode: the bases in the segment are an index sequence used to identify the sample being sequenced
22    SampleBarcode = b'B',
23    /// Molecular Barcode: the bases in the segment are an index sequence used to identify the unique source molecule being sequence (i.e. a UMI)
24    MolecularBarcode = b'M',
25    /// Skip: the bases in the segment should be skipped or ignored, for example if they are monotemplate sequence generated by the library preparation
26    Skip = b'S',
27    // Cellular Barcode: the bases in the segment are an index sequence used to identify the unique cell being sequenced
28    CellularBarcode = b'C',
29}
30
31impl SegmentType {
32    /// Returns the character representation of this segment type.
33    pub fn value(&self) -> char {
34        let value = *self as u8;
35        value as char
36    }
37}
38
39impl TryFrom<char> for SegmentType {
40    type Error = ReadStructureError;
41
42    /// Returns the segment type given the character representation.
43    ///
44    /// # Errors
45    ///
46    /// - If `SegmentType` not valid
47    fn try_from(value: char) -> Result<Self, Self::Error> {
48        match value {
49            'T' => Ok(SegmentType::Template),
50            'B' => Ok(SegmentType::SampleBarcode),
51            'M' => Ok(SegmentType::MolecularBarcode),
52            'S' => Ok(SegmentType::Skip),
53            'C' => Ok(SegmentType::CellularBarcode),
54            _ => Err(ReadStructureError::ReadSegmentTypeInvalid(value)),
55        }
56    }
57}
58
59impl TryFrom<u8> for SegmentType {
60    type Error = ReadStructureError;
61
62    /// Returns the segment type given the byte representation.
63    ///
64    /// # Errors
65    ///
66    /// - If `SegmentType` not valid
67    fn try_from(value: u8) -> Result<Self, Self::Error> {
68        Self::try_from(value as char)
69    }
70}
71
72#[cfg(test)]
73mod test {
74    use std::convert::TryFrom;
75
76    use crate::{segment_type::SegmentType, ReadStructureError};
77    use strum::IntoEnumIterator;
78
79    #[test]
80    fn test_segment_type_round_trip() -> Result<(), ReadStructureError> {
81        assert_eq!(SegmentType::iter().len(), 5);
82        for tpe in SegmentType::iter() {
83            assert_eq!(SegmentType::try_from(tpe.value())?, tpe);
84        }
85        Ok(())
86    }
87
88    #[test]
89    fn test_invalid_segment_type() {
90        assert!(SegmentType::try_from(b'G').is_err());
91    }
92}