1#![feature(iter_array_chunks)]
2#![feature(associated_type_defaults)]
3
4use std::{marker::PhantomData};
5
6#[derive(Debug, Clone, PartialEq)]
8pub enum Nucleotide {
9 Adenine,
10 Cytosine,
11 Guanine,
12 Thymine,
13 Uracil,
14}
15
16#[derive(Debug, PartialEq)]
18pub struct Codon([Nucleotide; 3]);
19
20#[derive(Debug)]
22pub struct NucleicAcid<T> {
23 pub nucleotides: Vec<Nucleotide>,
26 pub _marker: PhantomData<T>,
28}
29
30#[derive(Debug)]
32pub struct Dna;
33#[derive(Debug)]
35pub struct Rna;
36
37pub type NucleicRna = NucleicAcid<Rna>;
38pub type NucleicDna = NucleicAcid<Dna>;
39
40pub trait NucleicBuild {
42 type Marker;
43 type Acid = NucleicAcid<Self::Marker>;
44
45 fn build(content: &str) -> Result<Self::Acid, String>;
46}
47
48pub trait NucleicConvert {
50 fn char_to_nucleotide(c: char) -> Result<Nucleotide, String>;
51}
52
53impl<M> NucleicBuild for NucleicAcid<M>
55where
56 NucleicAcid<M>: NucleicConvert,
57{
58 type Marker = M;
59
60 fn build(content: &str) -> Result<Self::Acid, String> {
61 let nucleotides: Result<Vec<_>, _> = content.chars()
62 .map(|c| Self::Acid::char_to_nucleotide(c))
63 .collect();
64
65 let nucleotides = nucleotides?;
66
67 Ok(Self::Acid { nucleotides, _marker: PhantomData::<Self::Marker>})
68 }
69}
70
71impl NucleicConvert for NucleicRna {
72 fn char_to_nucleotide(c: char) -> Result<Nucleotide, String> {
74 use Nucleotide::*;
75
76 Ok(match c.to_ascii_uppercase() {
77 'A' => Adenine,
78 'C' => Cytosine,
79 'G' => Guanine,
80 'U' => Uracil,
81 x => Err(format!("{x}: not a valid character"))?,
82 })
83 }
84}
85
86impl NucleicRna {
87 pub fn into_codons(self) -> Vec<Codon> {
89 self.nucleotides.into_iter()
90 .array_chunks::<3>()
91 .map(|x| Codon(x))
92 .collect()
93 }
94}
95
96
97
98impl NucleicConvert for NucleicDna {
99 fn char_to_nucleotide(c: char) -> Result<Nucleotide, String> {
101 use Nucleotide::*;
102
103 Ok(match c.to_ascii_uppercase() {
104 'A' => Adenine,
105 'C' => Cytosine,
106 'G' => Guanine,
107 'T' => Thymine,
108 x => Err(format!("{x}: not a valid character"))?,
109 })
110 }
111}
112
113impl From<NucleicDna> for NucleicRna {
114 fn from(mut value: NucleicDna) -> Self {
115 for x in value.nucleotides.iter_mut() {
116 if *x == Nucleotide::Thymine {
117 *x = Nucleotide::Uracil;
118 }
119 }
120
121 Self { nucleotides: value.nucleotides, _marker: PhantomData::<Rna>}
122 }
123}
124
125impl From<NucleicRna> for NucleicDna {
126 fn from(mut value: NucleicRna) -> Self {
127 for x in value.nucleotides.iter_mut() {
128 if *x == Nucleotide::Uracil {
129 *x = Nucleotide::Thymine;
130 }
131 }
132
133 Self { nucleotides: value.nucleotides, _marker: PhantomData::<Dna>}
134 }
135}
136
137#[cfg(test)]
138mod test {
139 use super::*;
140
141 #[test]
142 fn dna_example() {
143 let content = "tAgCaT";
144 let result = NucleicDna::build(content).unwrap();
145
146 use Nucleotide::*;
147 assert_eq!(result.nucleotides, vec![
148 Thymine, Adenine, Guanine,
149 Cytosine, Adenine, Thymine
150 ]);
151 }
152
153 #[test]
154 fn rna_example() {
155 let content = "cagGua";
156 let result = NucleicRna::build(content).unwrap();
157
158 use Nucleotide::*;
159 assert_eq!(result.nucleotides, vec![
160 Cytosine, Adenine, Guanine,
161 Guanine, Uracil, Adenine
162 ]);
163 }
164
165 #[test]
166 fn dna_to_rna() {
167 let content = "tAgCaT";
168 let dna = NucleicDna::build(content).unwrap();
169 let rna = NucleicRna::from(dna);
170
171 use Nucleotide::*;
172 assert_eq!(rna.nucleotides, vec![
173 Uracil, Adenine, Guanine,
174 Cytosine, Adenine, Uracil
175 ]);
176 }
177
178 #[test]
179 fn rna_to_dna() {
180 let content = "cagGua";
181 let rna = NucleicRna::build(content).unwrap();
182 let dna = NucleicDna::from(rna);
183
184 use Nucleotide::*;
185 assert_eq!(dna.nucleotides, vec![
186 Cytosine, Adenine, Guanine,
187 Guanine, Thymine, Adenine
188 ]);
189 }
190
191 #[test]
192 fn into_codons() {
193 let content = "cagGua";
194 let result = NucleicRna::build(content).unwrap();
195
196 let codons = result.into_codons();
197
198 use Nucleotide::*;
199 assert_eq!(codons, vec![
200 Codon([Cytosine, Adenine, Guanine]),
201 Codon([Guanine, Uracil, Adenine]),
202 ])
203 }
204}