1use std::str::FromStr;
4
5use omics_molecule::compound::Nucleotide;
6use thiserror::Error;
7
8pub mod snv;
9
10#[derive(Error, Debug)]
12pub enum Error {
13 #[error("unable to parse a variant from `{0}`")]
15 ParseError(String),
16}
17
18#[derive(Debug)]
20pub enum Variant<N: Nucleotide> {
21 SingleNucleotideVariation(snv::Variant<N>),
23}
24
25impl<N: Nucleotide> std::str::FromStr for Variant<N>
26where
27 <N as FromStr>::Err: std::fmt::Debug + std::fmt::Display,
28{
29 type Err = Error;
30
31 fn from_str(s: &str) -> Result<Self, Self::Err> {
32 if let Ok(snv) = s.parse::<snv::Variant<N>>() {
33 return Ok(Variant::SingleNucleotideVariation(snv));
34 }
35
36 Err(Error::ParseError(s.to_string()))
37 }
38}
39
40impl<N: Nucleotide> std::fmt::Display for Variant<N>
41where
42 <N as FromStr>::Err: std::fmt::Debug + std::fmt::Display,
43{
44 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
45 match self {
46 Variant::SingleNucleotideVariation(variant) => write!(f, "{variant}"),
47 }
48 }
49}
50
51#[cfg(test)]
52mod tests {
53 use omics_coordinate::Strand;
54 use omics_molecule::polymer::dna;
55
56 use super::*;
57
58 #[test]
59 fn it_parses_dna_snvs_correctly() -> Result<(), Box<dyn std::error::Error>> {
60 let variant = "seq0:+:1:A:C".parse::<Variant<dna::Nucleotide>>()?;
61 assert!(matches!(variant, Variant::SingleNucleotideVariation(_)));
62
63 match variant {
64 Variant::SingleNucleotideVariation(snv) => {
65 assert_eq!(snv.coordinate().contig().as_str(), "seq0");
66 assert_eq!(snv.coordinate().strand(), Strand::Positive);
67 assert_eq!(snv.coordinate().position().get(), 1);
68 assert_eq!(snv.reference(), dna::Nucleotide::A);
69 assert_eq!(snv.alternate(), dna::Nucleotide::C);
70 }
71 }
72
73 Ok(())
74 }
75
76 #[test]
77 fn it_errors_when_attempting_to_parse_invalid_variants()
78 -> Result<(), Box<dyn std::error::Error>> {
79 let err = "seq0:1:A".parse::<Variant<dna::Nucleotide>>().unwrap_err();
80 assert_eq!(err.to_string(), "unable to parse a variant from `seq0:1:A`");
81
82 let err = "seq0:1:A:".parse::<Variant<dna::Nucleotide>>().unwrap_err();
83 assert_eq!(
84 err.to_string(),
85 "unable to parse a variant from `seq0:1:A:`"
86 );
87
88 let err = "seq0:A:C:1"
89 .parse::<Variant<dna::Nucleotide>>()
90 .unwrap_err();
91 assert_eq!(
92 err.to_string(),
93 "unable to parse a variant from `seq0:A:C:1`"
94 );
95
96 Ok(())
97 }
98
99 #[test]
100 fn it_serializes_correctly() -> Result<(), Box<dyn std::error::Error>> {
101 let variant = "seq0:+:1:A:C".parse::<Variant<dna::Nucleotide>>()?;
102 assert_eq!(variant.to_string(), "seq0:+:1:A:C");
103
104 let variant = "seq0:+:1:A:C".parse::<Variant<dna::Nucleotide>>()?;
105 assert_eq!(variant.to_string(), "seq0:+:1:A:C");
106
107 Ok(())
108 }
109}