use std::{error, fmt, num, str::FromStr};
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum Number {
Count(usize),
AlternateBases,
ReferenceAlternateBases,
Samples,
Unknown,
}
impl Number {
pub const A: Self = Self::AlternateBases;
pub const R: Self = Self::ReferenceAlternateBases;
pub const G: Self = Self::Samples;
}
impl Default for Number {
fn default() -> Self {
Self::Count(1)
}
}
impl fmt::Display for Number {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Count(n) => write!(f, "{n}"),
Self::AlternateBases => f.write_str("A"),
Self::ReferenceAlternateBases => f.write_str("R"),
Self::Samples => f.write_str("G"),
Self::Unknown => f.write_str("."),
}
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum ParseError {
Empty,
Invalid(num::ParseIntError),
}
impl error::Error for ParseError {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
match self {
Self::Empty => None,
Self::Invalid(e) => Some(e),
}
}
}
impl fmt::Display for ParseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Empty => f.write_str("empty input"),
Self::Invalid(_) => f.write_str("invalid input"),
}
}
}
impl FromStr for Number {
type Err = ParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"" => Err(ParseError::Empty),
"A" => Ok(Self::AlternateBases),
"R" => Ok(Self::ReferenceAlternateBases),
"G" => Ok(Self::Samples),
"." => Ok(Self::Unknown),
_ => s.parse().map(Self::Count).map_err(ParseError::Invalid),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default() {
assert_eq!(Number::default(), Number::Count(1));
}
#[test]
fn test_fmt() {
assert_eq!(Number::Count(1).to_string(), "1");
assert_eq!(Number::AlternateBases.to_string(), "A");
assert_eq!(Number::ReferenceAlternateBases.to_string(), "R");
assert_eq!(Number::Samples.to_string(), "G");
assert_eq!(Number::Unknown.to_string(), ".");
}
#[test]
fn test_from_str() {
assert_eq!("1".parse(), Ok(Number::Count(1)));
assert_eq!("A".parse(), Ok(Number::AlternateBases));
assert_eq!("R".parse(), Ok(Number::ReferenceAlternateBases));
assert_eq!("G".parse(), Ok(Number::Samples));
assert_eq!(".".parse(), Ok(Number::Unknown));
assert_eq!("".parse::<Number>(), Err(ParseError::Empty));
assert!(matches!(
"Noodles".parse::<Number>(),
Err(ParseError::Invalid(_))
));
}
}