use anyhow::{bail, Result};
use crate::{
traits::{ChromBounds, IntervalBounds, SetError, ValueBounds},
types::{iterator::ComplementIter, IntervalIterOwned},
IntervalContainer,
};
type ComplementIterOwned<I, C, T> = ComplementIter<IntervalIterOwned<I, C, T>, I, C, T>;
impl<I, C, T> IntervalContainer<I, C, T>
where
I: IntervalBounds<C, T>,
C: ChromBounds,
T: ValueBounds,
{
pub fn complement(self) -> Result<ComplementIterOwned<I, C, T>> {
if self.is_sorted() {
Ok(self.complement_unchecked())
} else {
bail!(SetError::UnsortedSet)
}
}
pub fn complement_unchecked(self) -> ComplementIterOwned<I, C, T> {
ComplementIter::new(self.into_iter())
}
}
#[cfg(test)]
mod testing {
use crate::{
traits::{ChromBounds, IntervalBounds, ValueBounds},
BaseInterval, Bed3, IntervalContainer,
};
fn validate_records<I, C, T>(obs: &[I], exp: &[I])
where
I: IntervalBounds<C, T>,
C: ChromBounds,
T: ValueBounds,
{
assert_eq!(obs.len(), exp.len());
for (obs, exp) in obs.iter().zip(exp.iter()) {
assert!(obs.eq(exp));
}
}
#[test]
fn complement_unsorted() {
let intervals = vec![BaseInterval::new(10, 20), BaseInterval::new(30, 40)];
let set = IntervalContainer::from_iter(intervals);
assert!(set.complement().is_err());
}
#[test]
fn complement_unmerged_boundary() {
let intervals = vec![BaseInterval::new(10, 20), BaseInterval::new(20, 30)];
let set = IntervalContainer::from_iter(intervals);
let comp_iter = set.complement();
assert!(comp_iter.is_err());
}
#[test]
fn complement_unmerged_overlapping() {
let intervals = vec![BaseInterval::new(10, 20), BaseInterval::new(18, 30)];
let set = IntervalContainer::from_iter(intervals);
let comp_iter = set.complement();
assert!(comp_iter.is_err());
}
#[test]
fn complement_a() {
let intervals = vec![BaseInterval::new(10, 20), BaseInterval::new(30, 40)];
let expected = vec![BaseInterval::new(20, 30)];
let set = IntervalContainer::from_unsorted(intervals);
let comp_iter = set.complement().unwrap();
let complements: Vec<_> = comp_iter.collect();
validate_records(&complements, &expected);
}
#[test]
fn complement_b() {
let intervals = vec![
BaseInterval::new(10, 20),
BaseInterval::new(30, 40),
BaseInterval::new(50, 60),
];
let expected = vec![BaseInterval::new(20, 30), BaseInterval::new(40, 50)];
let set = IntervalContainer::from_unsorted(intervals);
let comp_iter = set.complement().unwrap();
let complements: Vec<_> = comp_iter.collect();
validate_records(&complements, &expected);
}
#[test]
fn complement_c() {
let intervals = vec![
Bed3::new(1, 10, 20),
Bed3::new(1, 30, 40),
Bed3::new(2, 50, 60),
];
let expected = vec![Bed3::new(1, 20, 30)];
let set = IntervalContainer::from_unsorted(intervals);
let comp_iter = set.complement().unwrap();
let complements: Vec<_> = comp_iter.collect();
validate_records(&complements, &expected);
}
#[test]
fn complement_d() {
let intervals = vec![
Bed3::new(1, 10, 20),
Bed3::new(1, 30, 40),
Bed3::new(2, 10, 20),
Bed3::new(2, 30, 40),
];
let expected = vec![Bed3::new(1, 20, 30), Bed3::new(2, 20, 30)];
let set = IntervalContainer::from_unsorted(intervals);
let comp_iter = set.complement().unwrap();
let complements: Vec<_> = comp_iter.collect();
validate_records(&complements, &expected);
}
}