use super::Position;
use core::cmp::{max, min};
use core::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Range {
pub start: Position,
pub end: Position,
}
impl Range {
#[must_use]
pub fn new(start: Position, end: Position) -> Self {
if start.offset <= end.offset {
Self { start, end }
} else {
Self {
start: end,
end: start,
}
}
}
#[must_use]
pub const fn empty(pos: Position) -> Self {
Self {
start: pos,
end: pos,
}
}
#[must_use]
pub const fn is_empty(&self) -> bool {
self.start.offset == self.end.offset
}
#[must_use]
pub const fn len(&self) -> usize {
self.end.offset.saturating_sub(self.start.offset)
}
#[must_use]
pub const fn contains(&self, pos: Position) -> bool {
pos.offset >= self.start.offset && pos.offset < self.end.offset
}
#[must_use]
pub const fn overlaps(&self, other: &Self) -> bool {
self.start.offset < other.end.offset && other.start.offset < self.end.offset
}
#[must_use]
pub fn extend_to(&self, pos: Position) -> Self {
Self {
start: Position::new(min(self.start.offset, pos.offset)),
end: Position::new(max(self.end.offset, pos.offset)),
}
}
#[must_use]
pub fn union(&self, other: &Self) -> Self {
Self {
start: Position::new(min(self.start.offset, other.start.offset)),
end: Position::new(max(self.end.offset, other.end.offset)),
}
}
#[must_use]
pub fn intersection(&self, other: &Self) -> Option<Self> {
let start = max(self.start.offset, other.start.offset);
let end = min(self.end.offset, other.end.offset);
if start < end {
Some(Self::new(Position::new(start), Position::new(end)))
} else {
None
}
}
}
impl fmt::Display for Range {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.is_empty() {
write!(f, "{}", self.start)
} else {
write!(f, "{}-{}", self.start, self.end)
}
}
}