use std::{convert::TryFrom, mem, str::FromStr};
use strum::IntoEnumIterator;
use strum_macros::EnumIter;
use crate::ReadStructureError;
#[non_exhaustive]
#[derive(Debug, Copy, Clone, EnumIter, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[repr(u8)]
pub enum SegmentType {
Template = b'T',
SampleBarcode = b'B',
MolecularBarcode = b'M',
Skip = b'S',
CellularBarcode = b'C',
}
impl SegmentType {
pub fn value(&self) -> char {
let value = *self as u8;
value as char
}
}
impl TryFrom<char> for SegmentType {
type Error = ReadStructureError;
fn try_from(value: char) -> Result<Self, Self::Error> {
match value {
'T' => Ok(SegmentType::Template),
'B' => Ok(SegmentType::SampleBarcode),
'M' => Ok(SegmentType::MolecularBarcode),
'S' => Ok(SegmentType::Skip),
'C' => Ok(SegmentType::CellularBarcode),
_ => Err(ReadStructureError::ReadSegmentTypeInvalid(value)),
}
}
}
impl TryFrom<u8> for SegmentType {
type Error = ReadStructureError;
fn try_from(value: u8) -> Result<Self, Self::Error> {
Self::try_from(value as char)
}
}
impl FromStr for SegmentType {
type Err = ReadStructureError;
fn from_str(value: &str) -> Result<Self, Self::Err> {
if value.len() == 1 {
Self::try_from(value.chars().next().unwrap())
} else {
Err(ReadStructureError::ReadSegmentTypeStringInvalid(value.to_owned()))
}
}
}
#[cfg(test)]
mod test {
use std::convert::TryFrom;
use std::str::FromStr;
use crate::{ReadStructureError, segment_type::SegmentType};
use strum::IntoEnumIterator;
#[test]
fn test_segment_type_round_trip() -> Result<(), ReadStructureError> {
assert_eq!(SegmentType::iter().len(), 5);
for tpe in SegmentType::iter() {
assert_eq!(SegmentType::try_from(tpe.value())?, tpe);
}
Ok(())
}
#[test]
fn test_invalid_segment_type() {
assert!(SegmentType::try_from(b'G').is_err());
}
#[test]
fn test_segment_type_from_str() -> Result<(), ReadStructureError> {
let segment_types_char: [char; 5] = ['T', 'B', 'M', 'S', 'C'];
let segment_types_str: [&str; 5] = ["T", "B", "M", "S", "C"];
let mut iter = segment_types_str.iter().zip(segment_types_char.iter());
for (s, c) in iter {
assert_eq!(SegmentType::from_str(s)?, SegmentType::try_from(*c)?);
}
Ok(())
}
#[test]
fn test_invalid_segment_type_string() {
assert!(SegmentType::from_str("").is_err());
assert!(SegmentType::from_str("GG").is_err());
assert!(SegmentType::from_str("TG").is_err());
assert!(!SegmentType::from_str("T").is_err());
}
}