bio_seq/codec/masked/
dna.rs1use crate::codec::Codec;
2use crate::{Complement, ComplementMut, Maskable, MaskableMut}; #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Codec)]
9#[bits(4)]
10#[repr(u8)]
11pub enum Dna {
12 A = 0b1000,
13 C = 0b0100,
14 G = 0b0010,
15 T = 0b0001,
16
17 #[display('a')]
18 AMasked = 0b0111,
19 #[display('c')]
20 CMasked = 0b1011,
21 #[display('g')]
22 GMasked = 0b1101,
23 #[display('t')]
24 TMasked = 0b1110,
25
26 N = 0b0000,
27 #[display('n')]
28 NMasked = 0b1111,
29
30 #[display('-')]
31 #[alt(0b0011)]
32 Gap = 0b1100,
33
34 #[display('.')]
35 #[alt(0b0101)]
36 Pad = 0b1010,
37
38 #[display('?')]
39 Unknown1 = 0b0110,
40
41 #[display('!')]
42 Unknown2 = 0b1001,
43}
44
45impl ComplementMut for Dna {
46 fn comp(&mut self) {
48 let bits = self.to_bits();
49 *self = Self::unsafe_from_bits(
50 ((bits & 0b1000) >> 3)
51 | ((bits & 0b0100) >> 1)
52 | ((bits & 0b0010) << 1)
53 | ((bits & 0b0001) << 3),
54 );
55 }
56}
57
58impl Complement for Dna {}
59
60impl MaskableMut for Dna {
61 fn mask(&mut self) {
63 let b = *self as u8 ^ 0b1111;
64 *self = Dna::unsafe_from_bits(b);
65 }
66
67 fn unmask(&mut self) {
68 let b = *self as u8 ^ 0b1111;
69 *self = Dna::unsafe_from_bits(b);
70 }
71}
72
73impl Maskable for Dna {}
74
75#[cfg(test)]
76mod tests {
77 use crate::codec::masked;
78 use crate::prelude::*;
79
80 #[test]
81 fn iupac_comp() {
82 let a: masked::Dna = masked::Dna::A;
83 let t: masked::Dna = masked::Dna::T;
84 let c: masked::Dna = masked::Dna::C;
85 let g: masked::Dna = masked::Dna::G;
86 assert_eq!(t.to_comp(), a);
87 assert_eq!(c.to_comp(), g);
88
89 assert_ne!(t.to_comp(), c);
90 assert_ne!(c.to_comp(), c);
91
92 assert_eq!(c.to_comp(), g.to_comp().to_comp());
93 }
94
95 #[test]
96 fn mask_sequence() {
97 let seq = Seq::<masked::Dna>::try_from("A.TCGCgtcataN--A").unwrap();
98
99 assert_ne!(seq.to_mask().to_string(), "a.tcgcGTGATAN--a".to_string());
100 assert_eq!(seq.to_mask().to_string(), "a.tcgcGTCATAn--a".to_string());
101 }
102
103 #[test]
104 fn masked_comp() {
105 let seq = Seq::<masked::Dna>::try_from("A.TCGCgtcataN--A").unwrap();
106
107 assert_eq!(seq.to_comp().to_string(), "T.AGCGcagtatN--T".to_string());
108 }
109
110 #[test]
111 fn masked_revcomp() {
112 let seq = Seq::<masked::Dna>::try_from("A.TCGCgtcataN--A").unwrap();
113
114 assert_ne!(seq.to_revcomp().to_string(), "T--NtaagacGCGA.T".to_string());
115 assert_eq!(seq.to_revcomp().to_string(), "T--NtatgacGCGA.T".to_string());
116 }
117}