use crate::{
traits::{ChromBounds, IntervalBounds, ValueBounds},
Coordinates, Intersect, Overlap, Subtract,
};
pub trait Segment<C, T>: Coordinates<C, T> + Overlap<C, T>
where
C: ChromBounds,
T: ValueBounds,
{
#[must_use]
fn build_self<I: Coordinates<C, T>>(&self, other: &I) -> Self {
let mut sub = Self::from(other);
sub.update_all(self.chr(), &self.start(), &self.end());
sub
}
#[must_use]
fn build_other<I: Coordinates<C, T>>(&self, other: &I) -> Self {
let mut sub = Self::from(other);
sub.update_all(other.chr(), &other.start(), &other.end());
sub
}
fn insert_lhs<I: Coordinates<C, T>>(&self, other: &I, segments: &mut Vec<Self>) {
let sub = self.subtract(other).unwrap();
segments.extend(sub);
}
fn insert_center<I: Coordinates<C, T>>(&self, other: &I, segments: &mut Vec<Self>) {
if let Some(ix) = other.intersect(self) {
segments.push(ix);
}
}
fn insert_rhs<I: Coordinates<C, T>>(&self, other: &I, segments: &mut Vec<Self>) {
let sub = other.subtract(self).unwrap();
for s in sub {
segments.push(self.build_other(&s));
}
}
fn insert_internal_contained<I: Coordinates<C, T>>(&self, other: &I, segments: &mut Vec<Self>) {
let sub = self.subtract(other).unwrap();
segments.push(self.build_other(&sub[0]));
self.insert_center(other, segments);
segments.push(self.build_other(&sub[1]));
}
fn insert_external_contained<I: Coordinates<C, T>>(&self, other: &I, segments: &mut Vec<Self>) {
let sub = other.subtract(self).unwrap();
segments.push(self.build_other(&sub[0]));
self.insert_center(other, segments);
segments.push(self.build_other(&sub[1]));
}
fn insert_lh_overlap<I: Coordinates<C, T>>(&self, other: &I, segments: &mut Vec<Self>) {
self.insert_lhs(other, segments);
self.insert_center(other, segments);
self.insert_rhs(other, segments);
}
fn insert_rh_overlap<I: Coordinates<C, T>>(&self, other: &I, segments: &mut Vec<Self>) {
self.insert_rhs(other, segments);
self.insert_center(other, segments);
self.insert_lhs(other, segments);
}
fn run_overlap<I: Coordinates<C, T>>(&self, other: &I, segments: &mut Vec<Self>) {
if self.lt(other) {
self.insert_lh_overlap(other, segments);
} else {
self.insert_rh_overlap(other, segments);
}
}
fn insert_input<I: Coordinates<C, T>>(&self, other: &I, segments: &mut Vec<Self>) {
segments.push(self.build_self(other));
segments.push(self.build_other(other));
}
fn insert_self<I: Coordinates<C, T>>(&self, other: &I, segments: &mut Vec<Self>) {
segments.push(self.build_self(other));
}
fn run_internal_containment<I: Coordinates<C, T>>(&self, other: &I, segments: &mut Vec<Self>) {
if other.starts(self) {
self.insert_center(other, segments);
self.insert_lhs(other, segments);
} else if other.ends(self) {
self.insert_lhs(other, segments);
self.insert_center(other, segments);
} else {
self.insert_internal_contained(other, segments);
}
}
fn run_external_containment<I: Coordinates<C, T>>(&self, other: &I, segments: &mut Vec<Self>) {
if self.starts(other) {
self.insert_center(other, segments);
self.insert_rhs(other, segments);
} else if self.ends(other) {
self.insert_rhs(other, segments);
self.insert_center(other, segments);
} else {
self.insert_external_contained(other, segments);
}
}
#[must_use]
fn segment<I: IntervalBounds<C, T>>(&self, other: &I) -> Vec<Self> {
let mut segments = Vec::new();
if self.equals(other) {
self.insert_self(other, &mut segments);
} else if self.contains(other) {
self.run_internal_containment(other, &mut segments);
} else if other.contains(self) {
self.run_external_containment(other, &mut segments);
} else if self.overlaps(other) {
self.run_overlap(other, &mut segments);
} else {
self.insert_input(other, &mut segments);
}
segments
}
}
#[cfg(test)]
mod testing {
use super::*;
use crate::Bed3;
fn validate_segments<T: ValueBounds>(observed: &[Bed3<i32, T>], expected: &[Bed3<i32, T>]) {
assert_eq!(observed.len(), expected.len());
println!("Expected:");
for exp in expected {
println!("{exp:?}");
}
println!("Observed:");
for obs in observed {
println!("{obs:?}");
}
for (obs, exp) in observed.iter().zip(expected.iter()) {
assert_eq!(obs.chr(), exp.chr());
assert_eq!(obs.start(), exp.start());
assert_eq!(obs.end(), exp.end());
}
}
#[test]
fn non_overlapping() {
let iv1 = Bed3::new(1, 20, 30);
let iv2 = Bed3::new(1, 40, 50);
let expected = vec![Bed3::new(1, 20, 30), Bed3::new(1, 40, 50)];
let observed = iv1.segment(&iv2);
validate_segments(&observed, &expected);
}
#[test]
fn segments_equal() {
let iv1 = Bed3::new(1, 20, 30);
let iv2 = Bed3::new(1, 20, 30);
let expected = vec![Bed3::new(1, 20, 30)];
let observed = iv1.segment(&iv2);
validate_segments(&observed, &expected);
}
#[test]
fn segments_overlap_left() {
let iv1 = Bed3::new(1, 25, 35);
let iv2 = Bed3::new(1, 20, 30);
let expected = vec![
Bed3::new(1, 20, 25),
Bed3::new(1, 25, 30),
Bed3::new(1, 30, 35),
];
let observed = iv1.segment(&iv2);
validate_segments(&observed, &expected);
}
#[test]
fn segments_overlap_right() {
let iv1 = Bed3::new(1, 20, 30);
let iv2 = Bed3::new(1, 25, 35);
let expected = vec![
Bed3::new(1, 20, 25),
Bed3::new(1, 25, 30),
Bed3::new(1, 30, 35),
];
let observed = iv1.segment(&iv2);
validate_segments(&observed, &expected);
}
#[test]
fn segments_internal_containment() {
let iv1 = Bed3::new(1, 20, 40);
let iv2 = Bed3::new(1, 25, 35);
let expected = vec![
Bed3::new(1, 20, 25),
Bed3::new(1, 25, 35),
Bed3::new(1, 35, 40),
];
let observed = iv1.segment(&iv2);
validate_segments(&observed, &expected);
}
#[test]
fn segments_internal_starts() {
let iv1 = Bed3::new(1, 20, 40);
let iv2 = Bed3::new(1, 20, 30);
let expected = vec![Bed3::new(1, 20, 30), Bed3::new(1, 30, 40)];
let observed = iv1.segment(&iv2);
validate_segments(&observed, &expected);
}
#[test]
fn segments_internal_ends() {
let iv1 = Bed3::new(1, 20, 40);
let iv2 = Bed3::new(1, 30, 40);
let expected = vec![Bed3::new(1, 20, 30), Bed3::new(1, 30, 40)];
let observed = iv1.segment(&iv2);
validate_segments(&observed, &expected);
}
#[test]
fn segments_external_containment() {
let iv1 = Bed3::new(1, 25, 35);
let iv2 = Bed3::new(1, 20, 40);
let expected = vec![
Bed3::new(1, 20, 25),
Bed3::new(1, 25, 35),
Bed3::new(1, 35, 40),
];
let observed = iv1.segment(&iv2);
validate_segments(&observed, &expected);
}
#[test]
fn segments_external_starts() {
let iv1 = Bed3::new(1, 20, 30);
let iv2 = Bed3::new(1, 20, 40);
let expected = vec![Bed3::new(1, 20, 30), Bed3::new(1, 30, 40)];
let observed = iv1.segment(&iv2);
validate_segments(&observed, &expected);
}
#[test]
fn segments_external_ends() {
let iv1 = Bed3::new(1, 30, 40);
let iv2 = Bed3::new(1, 20, 40);
let expected = vec![Bed3::new(1, 20, 30), Bed3::new(1, 30, 40)];
let observed = iv1.segment(&iv2);
validate_segments(&observed, &expected);
}
}