use crate::codec::Codec;
use crate::{Complement, ComplementMut};
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(u8)]
pub enum Dna {
A = 0b00,
C = 0b01,
G = 0b10,
T = 0b11,
}
impl Codec for Dna {
const BITS: u8 = 2;
fn unsafe_from_bits(b: u8) -> Self {
debug_assert!(b < 4);
unsafe { std::mem::transmute(b & 0b11) }
}
fn try_from_bits(b: u8) -> Option<Self> {
if b < 4 {
Some(unsafe { std::mem::transmute::<u8, Dna>(b) })
} else {
None
}
}
fn unsafe_from_ascii(b: u8) -> Self {
Dna::unsafe_from_bits(((b << 1) + b) >> 3)
}
fn try_from_ascii(c: u8) -> Option<Self> {
match c {
b'A' => Some(Dna::A),
b'C' => Some(Dna::C),
b'G' => Some(Dna::G),
b'T' => Some(Dna::T),
_ => None,
}
}
fn to_char(self) -> char {
match self {
Dna::A => 'A',
Dna::C => 'C',
Dna::G => 'G',
Dna::T => 'T',
}
}
fn to_bits(self) -> u8 {
self as u8
}
fn items() -> impl Iterator<Item = Self> {
vec![Dna::A, Dna::C, Dna::G, Dna::T].into_iter()
}
}
impl ComplementMut for Dna {
fn comp(&mut self) {
*self = Dna::unsafe_from_bits(*self as u8 ^ 0b11);
}
}
impl Complement for Dna {}
#[cfg(test)]
mod tests {
use crate::prelude::*;
#[test]
fn dna_kmer_equality() {
assert_eq!(
Kmer::<Dna, 8>::try_from(dna!("TGCACATG")).unwrap(),
Kmer::<Dna, 8>::try_from(dna!("TGCACATG")).unwrap()
);
assert_ne!(
Kmer::<Dna, 7>::try_from(dna!("GTGACGA")).unwrap(),
Kmer::<Dna, 7>::try_from(dna!("GTGAAGA")).unwrap()
);
}
#[test]
fn dna_kmer_macro() {
assert_eq!(
kmer!("TGCACATG"),
Kmer::<Dna, 8>::try_from(dna!("TGCACATG")).unwrap()
);
assert_ne!(
kmer!("GTGACGA"),
Kmer::<Dna, 7>::try_from(dna!("GTGAAGA")).unwrap()
);
}
}