use mafft_types::SequenceSet;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct IllegalResidue {
pub seq_index: usize,
pub position: usize,
pub byte: u8,
}
pub fn seqcheck_alphabet(set: &SequenceSet) -> &'static [u8] {
if set.seq_type.is_nucleotide() {
&mafft_scoring::DNA_ALPHABET.chars
} else {
&mafft_scoring::PROTEIN_ALPHABET.chars
}
}
pub fn find_illegal_residue(set: &SequenceSet) -> Option<IllegalResidue> {
let alphabet = seqcheck_alphabet(set);
for (seq_index, s) in set.sequences.iter().enumerate() {
if let Some((position, &byte)) =
s.data.iter().enumerate().find(|(_, c)| !alphabet.contains(c))
{
return Some(IllegalResidue { seq_index, position, byte });
}
}
None
}
#[cfg(test)]
mod tests {
use super::*;
use mafft_types::{SeqType, Sequence};
fn set(rows: &[&[u8]], seq_type: SeqType) -> SequenceSet {
SequenceSet {
sequences: rows
.iter()
.enumerate()
.map(|(i, d)| Sequence { name: format!("s{i}"), data: d.to_vec() })
.collect(),
seq_type,
}
}
#[test]
fn protein_alphabet_is_c_locaminod() {
assert_eq!(find_illegal_residue(&set(&[b"ARNDCQEGHILKMFPSTWYVBZXJ.-"], SeqType::Protein)), None);
assert_eq!(
find_illegal_residue(&set(&[b"MKALVUWQ", b"MKALVOWQ"], SeqType::Protein)),
Some(IllegalResidue { seq_index: 0, position: 5, byte: b'U' })
);
assert_eq!(
find_illegal_residue(&set(&[b"MKALVWQ", b"MKALVOWQ"], SeqType::Protein)),
Some(IllegalResidue { seq_index: 1, position: 5, byte: b'O' })
);
assert_eq!(
find_illegal_residue(&set(&[b"MKalv"], SeqType::Protein)).map(|r| r.byte),
Some(b'a')
);
}
#[test]
fn nucleotide_alphabet_is_c_locaminon() {
assert_eq!(find_illegal_residue(&set(&[b"agctunbdhkmrsvwyx-"], SeqType::Dna)), None);
assert_eq!(find_illegal_residue(&set(&[b"agcu"], SeqType::Rna)), None);
assert_eq!(
find_illegal_residue(&set(&[b"acgt", b"acg.t"], SeqType::Dna)),
Some(IllegalResidue { seq_index: 1, position: 3, byte: b'.' })
);
assert_eq!(find_illegal_residue(&set(&[b"acgtO"], SeqType::Dna)), None);
assert_eq!(find_illegal_residue(&set(&[b"acgto"], SeqType::Dna)).map(|r| r.byte), Some(b'o'));
}
#[test]
fn unknown_type_uses_the_protein_alphabet() {
assert_eq!(find_illegal_residue(&set(&[b"ACGT."], SeqType::Unknown)), None);
assert_eq!(find_illegal_residue(&set(&[b"acgt"], SeqType::Unknown)).map(|r| r.byte), Some(b'a'));
}
}