omics_molecule/polymer/dna.rs
1//! Deoxyribonucleic Acid.
2
3mod nucleotide;
4
5pub use nucleotide::Nucleotide;
6use thiserror::Error;
7
8/// An error related to a [`Molecule`].
9#[derive(Error, Debug)]
10pub enum Error {
11 /// An error when processing a [`Nucleotide`].
12 #[error(transparent)]
13 NucleotideError(#[from] nucleotide::Error),
14}
15
16/// A molecule representing Deoxyribonucleic Acid, otherwise known as DNA.
17#[derive(Debug)]
18pub struct Molecule(Vec<Nucleotide>);
19
20impl Molecule {
21 /// Gets the inner [`Vec<Nucleotide>`] by reference.
22 ///
23 /// # Examples
24 ///
25 /// ```
26 /// use omics_molecule::polymer::dna::Molecule;
27 ///
28 /// let m = "ACGT".parse::<Molecule>()?;
29 /// assert_eq!(m.inner().len(), 4);
30 ///
31 /// # Ok::<(), Box<dyn std::error::Error>>(())
32 /// ```
33 pub fn inner(&self) -> &Vec<Nucleotide> {
34 self.0.as_ref()
35 }
36
37 /// Consumes the [`Molecule`] and returns the inner [`Vec<Nucleotide>`].
38 ///
39 /// # Examples
40 ///
41 /// ```
42 /// use omics_molecule::polymer::dna::Molecule;
43 /// use omics_molecule::polymer::dna::Nucleotide;
44 ///
45 /// let m = "ACGT".parse::<Molecule>()?;
46 /// let nucleotides = m.into_inner();
47 ///
48 /// assert_eq!(
49 /// nucleotides,
50 /// vec![Nucleotide::A, Nucleotide::C, Nucleotide::G, Nucleotide::T,]
51 /// );
52 ///
53 /// # Ok::<(), Box<dyn std::error::Error>>(())
54 /// ```
55 pub fn into_inner(self) -> Vec<Nucleotide> {
56 self.0
57 }
58
59 /// Gets the GC content of this [`Molecule`].
60 ///
61 /// # Examples
62 ///
63 /// ```
64 /// use omics_molecule::polymer::dna::Molecule;
65 ///
66 /// let m = "ACGT".parse::<Molecule>()?;
67 /// assert_eq!(m.gc_content(), 0.5);
68 ///
69 /// # Ok::<(), Box<dyn std::error::Error>>(())
70 /// ```
71 pub fn gc_content(&self) -> f32 {
72 let numerator = self
73 .0
74 .iter()
75 .filter(|n| *n == &Nucleotide::C || *n == &Nucleotide::G)
76 .count();
77
78 numerator as f32 / self.0.len() as f32
79 }
80}
81
82impl From<Vec<Nucleotide>> for Molecule {
83 fn from(v: Vec<Nucleotide>) -> Self {
84 Self(v)
85 }
86}
87
88impl std::str::FromStr for Molecule {
89 type Err = Error;
90
91 fn from_str(s: &str) -> Result<Self, Self::Err> {
92 s.chars()
93 .map(|c| Nucleotide::try_from(c).map_err(Error::NucleotideError))
94 .collect::<Result<Vec<_>, Error>>()
95 .map(Self::from)
96 }
97}
98
99#[cfg(test)]
100mod tests {
101 use super::*;
102
103 #[test]
104 fn it_creates_a_molecule_from_a_vec_of_nucleotides() {
105 let nucleotides = vec![Nucleotide::A, Nucleotide::C, Nucleotide::G, Nucleotide::T];
106
107 let dna = Molecule::from(nucleotides);
108 assert_eq!(dna.inner().len(), 4);
109 }
110
111 #[test]
112 fn it_parses_a_molecule_from_a_valid_string() -> Result<(), Box<dyn std::error::Error>> {
113 Ok("ACGT".parse::<Molecule>().map(|_| ())?)
114 }
115
116 #[test]
117 fn it_fails_to_parse_a_molecule_from_an_invalid_string() {
118 let err = "QQQQ".parse::<Molecule>().unwrap_err();
119 assert_eq!(err.to_string(), "invalid nucleotide `Q`");
120 }
121}