use std::fmt;
use std::ops::Add;
use std::str::FromStr;
use serde::{Deserialize, Serialize};
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum Frame {
None, Zero, One, Two, }
impl fmt::Display for Frame {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{}",
match self {
Frame::None => ".",
Frame::Zero => "0",
Frame::One => "1",
Frame::Two => "2",
}
)
}
}
impl Frame {
pub fn from_int(s: u32) -> Result<Self, String> {
match s % 3 {
0 => Ok(Frame::Zero),
1 => Ok(Frame::One),
2 => Ok(Frame::Two),
_ => Err(format!("invalid frame indicator {}", s)),
}
}
pub fn from_gtf(s: &str) -> Result<Self, String> {
Frame::from_str(s)
}
pub fn from_refgene(s: &str) -> Result<Self, String> {
match s {
"-1" => Ok(Frame::None),
"." => Ok(Frame::None), "0" => Ok(Frame::Zero),
"1" => Ok(Frame::Two), "2" => Ok(Frame::One), _ => Err(format!("invalid frame indicator {}", s)),
}
}
pub fn to_gtf(&self) -> String {
self.to_string()
}
pub fn to_refgene(&self) -> String {
match self {
Frame::Zero => "0",
Frame::One => "2", Frame::Two => "1", _ => "-1",
}
.to_string()
}
pub fn is_known(&self) -> bool {
matches!(self, Frame::Zero | Frame::One | Frame::Two)
}
fn to_int(self) -> Result<u32, String> {
match self {
Frame::Zero => Ok(0),
Frame::One => Ok(1),
Frame::Two => Ok(2),
_ => Err("unspecified frame cannot be converted to int".to_string()),
}
}
}
impl Add for Frame {
type Output = Result<Self, String>;
fn add(self, other: Self) -> Result<Self, String> {
match (self.to_int(), other.to_int()) {
(Ok(x), Ok(y)) => Self::from_int((x + y) % 3),
(Ok(_), _) => Ok(self),
(_, Ok(_)) => Ok(other),
_ => Err("unable to add two unspecified frames".to_string()),
}
}
}
impl FromStr for Frame {
type Err = String;
fn from_str(s: &str) -> Result<Self, String> {
match s {
"-1" => Ok(Frame::None),
"0" => Ok(Frame::Zero),
"1" => Ok(Frame::One),
"2" => Ok(Frame::Two),
"." => Ok(Frame::None),
_ => Err(format!("invalid frame indicator {}", s)),
}
}
}