use anyhow::anyhow;
use anyhow::Result;
use bstr::BStr;
use rayon::prelude::*;
use std::ops::Range;
pub fn generate_unmaped_intervals(
input: &[Range<usize>],
total_length: usize,
) -> Vec<Range<usize>> {
let mut result = Vec::new();
if input.is_empty() {
result.push(0..total_length);
return result;
}
let mut current_start = 0;
for range in input.iter() {
if current_start < range.start {
result.push(current_start..range.start);
}
current_start = range.end;
}
if current_start < total_length - 1 {
result.push(current_start..total_length - 1);
}
result
}
pub fn remove_intervals_and_keep_left<'a>(
seq: &'a [u8],
intervals: &[Range<usize>],
) -> Result<(Vec<&'a BStr>, Vec<Range<usize>>)> {
let mut intervals = intervals.to_vec();
intervals.par_sort_by(|a: &Range<usize>, b: &Range<usize>| a.start.cmp(&b.start));
let selected_intervals = generate_unmaped_intervals(&intervals, seq.len());
let selected_seq = selected_intervals
.par_iter()
.map(|interval| {
if interval.start < seq.len() {
Ok(seq[interval.start..interval.end].as_ref())
} else {
Err(anyhow!(format!("invalid {:?}", interval)))
}
})
.collect::<Result<Vec<_>>>()?;
Ok((selected_seq, selected_intervals))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_remove_intervals_and_keep_left() {
let seq = b"abcdefghijklmnopqrstuvwxyz";
let intervals = vec![1..5, 10..15, 20..25];
let (seq, _inters) = remove_intervals_and_keep_left(seq, &intervals).unwrap();
assert_eq!(seq, vec!["a", "fghij", "pqrst"]);
let seq = b"abcdefghijklmnopqrstuvwxyz";
let intervals = vec![5..10, 15..20];
let (seq, _inters) = remove_intervals_and_keep_left(seq, &intervals).unwrap();
assert_eq!(seq, vec!["abcde", "klmno", "uvwxy"]);
}
#[allow(clippy::single_range_in_vec_init)]
#[test]
fn test_generate_unmaped_intervals() {
let intervals = vec![8100..8123];
let seq_len = 32768;
let selected_intervals = generate_unmaped_intervals(&intervals, seq_len);
assert_eq!(selected_intervals, vec![0..8100, 8123..32767]);
}
}