use crate::codec::{Codec, dna::Dna};
use crate::seq::{Seq, SeqArray, SeqSlice};
use crate::{Complement, ComplementMut};
const IUPAC_COMPLEMENT_TABLE: [u8; 16] = {
let mut table = [0; 16];
table[Iupac::A as usize] = Iupac::T as u8;
table[Iupac::C as usize] = Iupac::G as u8;
table[Iupac::G as usize] = Iupac::C as u8;
table[Iupac::T as usize] = Iupac::A as u8;
table[Iupac::Y as usize] = Iupac::R as u8;
table[Iupac::R as usize] = Iupac::Y as u8;
table[Iupac::W as usize] = Iupac::W as u8;
table[Iupac::S as usize] = Iupac::S as u8;
table[Iupac::K as usize] = Iupac::M as u8;
table[Iupac::M as usize] = Iupac::K as u8;
table[Iupac::D as usize] = Iupac::H as u8;
table[Iupac::V as usize] = Iupac::B as u8;
table[Iupac::H as usize] = Iupac::D as u8;
table[Iupac::B as usize] = Iupac::V as u8;
table[Iupac::N as usize] = Iupac::N as u8;
table
};
impl From<Iupac> for u8 {
fn from(b: Iupac) -> u8 {
b as u8
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Codec)]
#[bits(4)]
#[repr(u8)]
pub enum Iupac {
A = 0b1000,
C = 0b0100,
G = 0b0010,
T = 0b0001,
R = 0b1010,
Y = 0b0101,
S = 0b0110,
W = 0b1001,
K = 0b0011,
M = 0b1100,
B = 0b0111,
D = 0b1011,
H = 0b1101,
V = 0b1110,
N = 0b1111,
#[display('-')]
X = 0b0000,
}
impl From<Dna> for Iupac {
fn from(dna: Dna) -> Self {
match dna {
Dna::A => Iupac::A,
Dna::C => Iupac::C,
Dna::G => Iupac::G,
Dna::T => Iupac::T,
}
}
}
impl Seq<Iupac> {
pub fn contains(&self, rhs: &SeqSlice<Iupac>) -> bool {
if rhs.len() != self.len() {
return false;
}
self.as_ref() & rhs == rhs
}
}
impl<const N: usize, const W: usize> SeqArray<Iupac, N, W> {
pub fn contains(&self, rhs: &SeqSlice<Iupac>) -> bool {
if N != rhs.len() {
return false;
}
self.as_ref() & rhs == rhs
}
}
impl SeqSlice<Iupac> {
pub fn contains(&self, rhs: &SeqSlice<Iupac>) -> bool {
if self.len() != rhs.len() {
return false;
}
self & rhs == rhs
}
}
impl ComplementMut for Iupac {
fn comp(&mut self) {
*self = Iupac::unsafe_from_bits(IUPAC_COMPLEMENT_TABLE[*self as usize]);
}
}
impl Complement for Iupac {}
#[cfg(test)]
mod tests {
use crate::prelude::*;
#[test]
fn iupac_ops() {
let seq = iupac!("AGCTNNCAGTCGACGTATGTA");
let pattern = iupac!("AYG");
let matches: Vec<Seq<Iupac>> = seq
.windows(pattern.len())
.filter(|w| pattern.contains(w))
.collect();
assert_eq!(matches, vec![iupac!("ACG"), iupac!("ATG")]);
}
#[test]
fn iupac_complement() {
assert_eq!(
iupac!("AGCTYRWSKMDVHBN").to_comp(),
iupac!("TCGARYWSMKHBDVN")
);
}
}