1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
use itertools::Itertools;
use crate::{AminoAcid, SequenceElement};
/// A protease defined by it ability to cut at any site identified by the right amino acids at the n and c terminal.
/// Each position is identified by an option, a none means that there is no specificity at this position. If there is
/// a specificity at a certain position any amino acid that is contained in the set is allowed (see
/// [`crate::CheckedAminoAcid::canonical_identical`]).
pub struct Protease {
/// The amino acids n terminal of the cut site.
pub n_term: Vec<Option<Vec<AminoAcid>>>,
/// The amino acids c terminal of the cut site.
pub c_term: Vec<Option<Vec<AminoAcid>>>,
}
impl Protease {
/// Define a simple protease that cuts exactly between the specified sequences.
pub fn new(n_term: &[AminoAcid], c_term: &[AminoAcid]) -> Self {
Self {
n_term: n_term.iter().map(|aa| Some(vec![*aa])).collect_vec(),
c_term: c_term.iter().map(|aa| Some(vec![*aa])).collect_vec(),
}
}
/// Define a protease that cuts on the n terminal side of the provided amino acids.
pub fn n_terminal_of(residues: &[AminoAcid]) -> Self {
Self {
n_term: vec![Some(residues.to_vec())],
c_term: Vec::new(),
}
}
/// Define a protease that cuts on the c terminal side of the provided amino acids.
pub fn c_terminal_of(residues: &[AminoAcid]) -> Self {
Self {
c_term: vec![Some(residues.to_vec())],
n_term: Vec::new(),
}
}
/// All locations in the given sequence where this protease could cut
pub fn match_locations<T>(&self, sequence: &[SequenceElement<T>]) -> Vec<usize> {
(self.n_term.len()..sequence.len() - self.c_term.len())
.filter(|i| self.matches_at(&sequence[i - self.n_term.len()..i + self.c_term.len()]))
.collect_vec()
}
fn matches_at<T>(&self, slice: &[SequenceElement<T>]) -> bool {
debug_assert!(slice.len() == self.n_term.len() + self.c_term.len());
'positions: for (actual, pattern) in slice
.iter()
.zip(self.n_term.iter().chain(self.c_term.iter()))
{
if let Some(pattern) = pattern {
for option in pattern {
if option.canonical_identical(actual.aminoacid.aminoacid()) {
continue 'positions;
}
}
return false;
}
}
true
}
}