use std::ops::Range;
use rle::{HasLength, MergableSpan, SplitableSpan, SplitableSpanHelpers};
use crate::dtrange::DTRange;
#[cfg(feature = "serde")]
use serde_crate::{Deserialize};
#[derive(Copy, Clone, Debug, Eq, Default)] #[cfg_attr(feature = "serde", derive(Deserialize), serde(crate="serde_crate"))]
pub struct RangeRev {
#[cfg_attr(feature = "serde", serde(flatten))]
pub span: DTRange,
pub fwd: bool,
}
impl RangeRev {
#[allow(unused)]
pub fn time_at_offset(&self, offset: usize) -> usize {
if self.fwd {
self.span.start + offset
} else {
self.span.end - offset - 1
}
}
pub fn range(&self, offset_start: usize, offset_end: usize) -> DTRange {
debug_assert!(offset_start <= offset_end);
debug_assert!(self.span.start + offset_start <= self.span.end);
debug_assert!(self.span.start + offset_end <= self.span.end);
if self.fwd {
DTRange {
start: self.span.start + offset_start,
end: self.span.start + offset_end
}
} else {
DTRange {
start: self.span.end - offset_end,
end: self.span.end - offset_start
}
}
}
}
impl From<DTRange> for RangeRev {
fn from(target: DTRange) -> Self {
RangeRev {
span: target,
fwd: true,
}
}
}
impl From<Range<usize>> for RangeRev {
fn from(range: Range<usize>) -> Self {
RangeRev {
span: range.into(),
fwd: true,
}
}
}
impl PartialEq for RangeRev {
fn eq(&self, other: &Self) -> bool {
self.span == other.span && (self.fwd == other.fwd || self.span.len() <= 1)
}
}
impl HasLength for RangeRev {
fn len(&self) -> usize { self.span.len() }
}
impl SplitableSpanHelpers for RangeRev {
fn truncate_h(&mut self, at: usize) -> Self {
RangeRev {
span: if self.fwd {
self.span.truncate(at)
} else {
self.span.truncate_keeping_right(self.len() - at)
},
fwd: self.fwd,
}
}
}
impl MergableSpan for RangeRev {
fn can_append(&self, other: &Self) -> bool {
let self_len_1 = self.len() == 1;
let other_len_1 = other.len() == 1;
if (self_len_1 || self.fwd) && (other_len_1 || other.fwd)
&& other.span.start == self.span.end {
return true;
}
if (self_len_1 || !self.fwd) && (other_len_1 || !other.fwd)
&& other.span.end == self.span.start {
return true;
}
false
}
fn append(&mut self, other: Self) {
debug_assert!(self.can_append(&other));
self.fwd = other.span.start >= self.span.start;
if self.fwd {
self.span.end = other.span.end;
} else {
self.span.start = other.span.start;
}
}
}
#[cfg(test)]
mod test {
use rle::test_splitable_methods_valid;
use super::*;
#[test]
fn split_fwd_rev() {
let fwd = RangeRev {
span: (1..4).into(),
fwd: true
};
assert_eq!(fwd.split_h(1), (
RangeRev {
span: (1..2).into(),
fwd: true
},
RangeRev {
span: (2..4).into(),
fwd: true
}
));
let rev = RangeRev {
span: (1..4).into(),
fwd: false
};
assert_eq!(rev.split_h(1), (
RangeRev {
span: (3..4).into(),
fwd: false
},
RangeRev {
span: (1..3).into(),
fwd: false
}
));
}
#[test]
fn splitable_mergable() {
test_splitable_methods_valid(RangeRev {
span: (1..5).into(),
fwd: true
});
test_splitable_methods_valid(RangeRev {
span: (1..5).into(),
fwd: false
});
}
#[test]
fn at_offset() {
for fwd in [true, false] {
let span = RangeRev {
span: (1..5).into(),
fwd
};
for offset in 1..span.len() {
let (a, b) = span.split_h(offset);
assert_eq!(span.time_at_offset(offset - 1), a.time_at_offset(offset - 1));
assert_eq!(span.time_at_offset(offset), b.time_at_offset(0));
}
}
}
}