use anyhow::bail;
use crate::{
traits::{IntervalBounds, ValueBounds},
Bound, Find, Merge, SetSubtract,
};
pub trait Container<T, I>
where
Self: Sized,
I: IntervalBounds<T>,
T: ValueBounds,
{
fn new(records: Vec<I>) -> Self;
fn records(&self) -> &Vec<I>;
fn records_mut(&mut self) -> &mut Vec<I>;
fn is_sorted(&self) -> bool;
fn set_sorted(&mut self);
fn len(&self) -> usize {
self.records().len()
}
fn is_empty(&self) -> bool {
self.records().is_empty()
}
fn sort(&mut self) {
self.records_mut().sort_unstable_by(|a, b| a.coord_cmp(b));
self.set_sorted();
}
fn from_sorted(records: Vec<I>) -> anyhow::Result<Self> {
if Self::valid_interval_sorting(&records) {
Ok(Self::from_sorted_unchecked(records))
} else {
bail!("Intervals are unsorted!")
}
}
fn from_sorted_unchecked(records: Vec<I>) -> Self {
let mut set = Self::new(records);
set.set_sorted();
set
}
fn from_unsorted(records: Vec<I>) -> Self {
let mut set = Self::new(records);
set.sort();
set
}
fn valid_interval_sorting(records: &Vec<I>) -> bool {
records
.iter()
.enumerate()
.skip(1)
.map(|(idx, rec)| (rec, &records[idx - 1]))
.all(|(a, b)| a.coord_cmp(b).is_ge())
}
}
impl<C, T, I> Merge<T, I> for C
where
C: Container<T, I>,
I: IntervalBounds<T>,
T: ValueBounds,
{
}
impl<C, T, I> Find<T, I> for C
where
C: Container<T, I>,
I: IntervalBounds<T>,
T: ValueBounds,
{
type ContainerType = C;
}
impl<C, T, I> Bound<T, I> for C
where
C: Container<T, I>,
I: IntervalBounds<T>,
T: ValueBounds,
{
}
impl<C, T, I> SetSubtract<T, I> for C
where
C: Container<T, I>,
I: IntervalBounds<T>,
T: ValueBounds,
{
}
#[cfg(test)]
mod testing {
use super::Container;
use crate::{traits::Coordinates, types::Interval, IntervalSet};
struct CustomContainer {
records: Vec<Interval<usize>>,
is_sorted: bool,
}
impl Container<usize, Interval<usize>> for CustomContainer {
fn new(records: Vec<Interval<usize>>) -> Self {
Self {
records,
is_sorted: false,
}
}
fn records(&self) -> &Vec<Interval<usize>> {
&self.records
}
fn records_mut(&mut self) -> &mut Vec<Interval<usize>> {
&mut self.records
}
fn is_sorted(&self) -> bool {
self.is_sorted
}
fn set_sorted(&mut self) {
self.is_sorted = true;
}
}
#[test]
fn test_custom_container_init() {
let records = vec![Interval::new(10, 100); 4];
let container = CustomContainer {
records,
is_sorted: false,
};
assert_eq!(container.len(), 4);
assert_eq!(container.records()[0].start(), 10);
assert_eq!(container.records()[0].end(), 100);
}
#[test]
fn test_custom_container_sort() {
let records = vec![
Interval::new(20, 30), Interval::new(10, 20), Interval::new(15, 25), ];
let mut container = CustomContainer {
records,
is_sorted: false,
};
container.sort();
assert_eq!(container.records()[0].start(), 10);
assert_eq!(container.records()[1].start(), 15);
assert_eq!(container.records()[2].start(), 20);
}
#[test]
fn test_custom_container_empty() {
let records = Vec::new();
let container = CustomContainer {
records,
is_sorted: false,
};
assert!(container.is_empty());
}
#[test]
fn test_container_init_new() {
let records = vec![
Interval::new(15, 25),
Interval::new(10, 20),
Interval::new(5, 15),
];
let set = IntervalSet::new(records);
assert_eq!(set.len(), 3);
assert!(!set.is_sorted());
assert!(!set.is_empty());
assert_eq!(set.records()[0].start(), 15);
}
#[test]
fn test_container_init_from_sorted() {
let records = vec![
Interval::new(5, 10),
Interval::new(10, 15),
Interval::new(15, 20),
];
let set = IntervalSet::from_sorted(records).unwrap();
assert_eq!(set.len(), 3);
assert!(set.is_sorted());
assert!(!set.is_empty());
assert_eq!(set.records()[0].start(), 5);
}
#[test]
fn test_container_init_from_unsorted() {
let records = vec![
Interval::new(15, 25),
Interval::new(10, 20),
Interval::new(5, 15),
];
let set = IntervalSet::from_unsorted(records);
assert_eq!(set.len(), 3);
assert!(set.is_sorted());
assert!(!set.is_empty());
assert_eq!(set.records()[0].start(), 5);
}
#[test]
fn test_container_init_from_sorted_false_sorting() {
let records = vec![
Interval::new(10, 15),
Interval::new(5, 10),
Interval::new(15, 20),
];
let set = IntervalSet::from_sorted(records);
assert!(set.is_err());
}
}