1pub mod adapter_db;
12
13pub const IUPAC_MASKS: [u8; 256] = {
18 let mut masks = [0u8; 256];
19 let (a, c, g, t) = (1, 2, 4, 8);
20 let pairs: &[(u8, u8)] = &[
21 (b'A', a),
22 (b'C', c),
23 (b'G', g),
24 (b'T', t),
25 (b'U', t),
26 (b'M', a | c),
27 (b'R', a | g),
28 (b'W', a | t),
29 (b'S', c | g),
30 (b'Y', c | t),
31 (b'K', g | t),
32 (b'V', a | c | g),
33 (b'H', a | c | t),
34 (b'D', a | g | t),
35 (b'B', c | g | t),
36 (b'N', a | c | g | t),
37 ];
38 let mut i = 0;
39 while i < pairs.len() {
40 let (upper, mask) = pairs[i];
41 masks[upper as usize] = mask;
42 masks[(upper | 0x20) as usize] = mask;
44 i += 1;
45 }
46 masks
47};
48
49#[cfg(test)]
50mod tests {
51 use super::*;
52
53 #[test]
54 fn acgt_masks_are_one_hot() {
55 assert_eq!(IUPAC_MASKS[b'A' as usize], 0b0001);
56 assert_eq!(IUPAC_MASKS[b'C' as usize], 0b0010);
57 assert_eq!(IUPAC_MASKS[b'G' as usize], 0b0100);
58 assert_eq!(IUPAC_MASKS[b'T' as usize], 0b1000);
59 assert_eq!(IUPAC_MASKS[b'U' as usize], 0b1000, "U aliases T");
60 }
61
62 #[test]
63 fn lowercase_matches_uppercase() {
64 for b in b"ACGTUMRWSYKVHDBN" {
65 assert_eq!(
66 IUPAC_MASKS[*b as usize],
67 IUPAC_MASKS[(*b | 0x20) as usize],
68 "case mismatch for {:?}",
69 *b as char,
70 );
71 }
72 }
73
74 #[test]
75 fn n_matches_everything() {
76 for b in b"ACGT" {
77 assert_ne!(IUPAC_MASKS[*b as usize] & IUPAC_MASKS[b'N' as usize], 0);
78 }
79 }
80
81 #[test]
82 fn non_iupac_bytes_are_zero() {
83 assert_eq!(IUPAC_MASKS[b'Z' as usize], 0);
84 assert_eq!(IUPAC_MASKS[b'.' as usize], 0);
85 assert_eq!(IUPAC_MASKS[0_usize], 0);
86 }
87
88 #[test]
89 fn r_is_superset_of_a_and_g_only() {
90 let r = IUPAC_MASKS[b'R' as usize];
91 assert_ne!(r & IUPAC_MASKS[b'A' as usize], 0);
92 assert_ne!(r & IUPAC_MASKS[b'G' as usize], 0);
93 assert_eq!(r & IUPAC_MASKS[b'C' as usize], 0);
94 assert_eq!(r & IUPAC_MASKS[b'T' as usize], 0);
95 }
96}