use crate::normalize::boundary::Boundaries;
use crate::normalize::config::ShuffleDirection;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ShuffleResult {
pub start: u64,
pub end: u64,
pub shifted: bool,
}
pub fn shuffle(
ref_seq: &[u8],
alt_seq: &[u8],
start: u64,
end: u64,
boundaries: &Boundaries,
direction: ShuffleDirection,
) -> ShuffleResult {
let mut new_start = start;
let mut new_end = end;
match direction {
ShuffleDirection::ThreePrime => {
while new_end < boundaries.right {
let ref_idx = new_end as usize;
if ref_idx >= ref_seq.len() {
break;
}
if alt_seq.is_empty() {
let del_start_idx = new_start as usize;
if del_start_idx < ref_seq.len() && ref_seq[del_start_idx] == ref_seq[ref_idx] {
new_start += 1;
new_end += 1;
} else {
break;
}
} else {
let alt_idx = ((new_end - start) % alt_seq.len() as u64) as usize;
if ref_seq[ref_idx] == alt_seq[alt_idx] {
new_start += 1;
new_end += 1;
} else {
break;
}
}
}
}
ShuffleDirection::FivePrime => {
while new_start > boundaries.left {
let check_idx = new_start - 1;
let ref_idx = check_idx as usize;
if ref_idx >= ref_seq.len() {
break;
}
if alt_seq.is_empty() {
let del_end_idx = (new_end - 1) as usize;
if del_end_idx < ref_seq.len() && ref_seq[del_end_idx] == ref_seq[ref_idx] {
new_start -= 1;
new_end -= 1;
} else {
break;
}
} else {
let alt_idx =
alt_seq.len() - 1 - ((start - new_start) % alt_seq.len() as u64) as usize;
if ref_idx < ref_seq.len() && ref_seq[ref_idx] == alt_seq[alt_idx] {
new_start -= 1;
new_end -= 1;
} else {
break;
}
}
}
}
}
ShuffleResult {
start: new_start,
end: new_end,
shifted: new_start != start,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_shuffle_deletion_3prime() {
let ref_seq = b"ATGGGGGCAT";
let boundaries = Boundaries::new(0, 10);
let result = shuffle(
ref_seq,
&[], 3, 4, &boundaries,
ShuffleDirection::ThreePrime,
);
assert!(result.shifted);
assert_eq!(result.start, 6);
assert_eq!(result.end, 7);
}
#[test]
fn test_shuffle_deletion_5prime() {
let ref_seq = b"ATGGGGGCAT";
let boundaries = Boundaries::new(0, 10);
let result = shuffle(
ref_seq,
&[], 6, 7, &boundaries,
ShuffleDirection::FivePrime,
);
assert!(result.shifted);
assert_eq!(result.start, 2);
assert_eq!(result.end, 3);
}
#[test]
fn test_no_shuffle_needed() {
let ref_seq = b"ATGCATGCAT";
let boundaries = Boundaries::new(0, 10);
let result = shuffle(
ref_seq,
&[],
2,
3,
&boundaries,
ShuffleDirection::ThreePrime,
);
assert!(!result.shifted);
assert_eq!(result.start, 2);
assert_eq!(result.end, 3);
}
#[test]
fn test_shuffle_respects_boundary() {
let ref_seq = b"ATGGGGGCAT";
let boundaries = Boundaries::new(0, 5);
let result = shuffle(
ref_seq,
&[],
3,
4,
&boundaries,
ShuffleDirection::ThreePrime,
);
assert!(result.shifted);
assert_eq!(result.end, 5); }
}