Skip to main content

fastqc_rust/utils/
dna.rs

1// DNA sequence utilities shared across modules.
2
3/// Complement a single DNA base (uppercase).
4///
5/// Matches the complement logic used in both BAMFile.java's
6/// reverseComplement() and Contaminant.java's reverse complement computation.
7/// Non-ACGT bases (like N) are returned unchanged.
8pub fn complement_base(base: u8) -> u8 {
9    match base {
10        b'A' => b'T',
11        b'T' => b'A',
12        b'C' => b'G',
13        b'G' => b'C',
14        other => other,
15    }
16}
17
18/// Reverse complement a DNA sequence.
19///
20/// Replicates reverseComplement() from BAMFile.java and the
21/// reverse complement computation in Contaminant.java. Input is assumed to
22/// be uppercase (or is uppercased before complementing).
23pub fn reverse_complement(seq: &[u8]) -> Vec<u8> {
24    seq.iter()
25        .rev()
26        .map(|&b| complement_base(b.to_ascii_uppercase()))
27        .collect()
28}
29
30#[cfg(test)]
31mod tests {
32    use super::*;
33
34    #[test]
35    fn test_complement_base() {
36        assert_eq!(complement_base(b'A'), b'T');
37        assert_eq!(complement_base(b'T'), b'A');
38        assert_eq!(complement_base(b'C'), b'G');
39        assert_eq!(complement_base(b'G'), b'C');
40        assert_eq!(complement_base(b'N'), b'N');
41    }
42
43    #[test]
44    fn test_reverse_complement_basic() {
45        assert_eq!(reverse_complement(b"ACGT"), b"ACGT");
46        assert_eq!(reverse_complement(b"AAAA"), b"TTTT");
47        assert_eq!(reverse_complement(b"CCCC"), b"GGGG");
48        assert_eq!(reverse_complement(b"ATCG"), b"CGAT");
49    }
50
51    #[test]
52    fn test_reverse_complement_with_n() {
53        // N is kept as N (matches Java's default case)
54        assert_eq!(reverse_complement(b"ANCG"), b"CGNT");
55    }
56
57    #[test]
58    fn test_reverse_complement_empty() {
59        assert_eq!(reverse_complement(b""), b"");
60    }
61
62    #[test]
63    fn test_reverse_complement_single() {
64        assert_eq!(reverse_complement(b"A"), b"T");
65        assert_eq!(reverse_complement(b"N"), b"N");
66    }
67}