use core::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Default)]
pub struct Span {
pub start: u32,
pub end: u32,
}
impl Span {
#[must_use]
pub const fn new(start: u32, end: u32) -> Self {
Self { start, end }
}
#[must_use]
pub const fn empty_at(at: u32) -> Self {
Self { start: at, end: at }
}
#[must_use]
pub const fn len(self) -> u32 {
self.end.saturating_sub(self.start)
}
#[must_use]
pub const fn is_empty(self) -> bool {
self.end <= self.start
}
#[must_use]
pub const fn cover(self, other: Self) -> Self {
Self {
start: if self.start < other.start {
self.start
} else {
other.start
},
end: if self.end > other.end {
self.end
} else {
other.end
},
}
}
#[must_use]
pub const fn contains(self, at: u32) -> bool {
self.start <= at && at < self.end
}
#[must_use]
pub fn slice(self, source: &str) -> Option<&str> {
source.get(self.start as usize..self.end as usize)
}
}
impl fmt::Display for Span {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}..{}", self.start, self.end)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct LineColumn {
pub line: u32,
pub column: u32,
}
impl LineColumn {
#[must_use]
pub fn of(source: &str, offset: u32) -> Self {
let mut line = 1u32;
let mut column = 1u32;
for (index, ch) in source.char_indices() {
if index as u32 >= offset {
break;
}
if ch == '\n' {
line = line.saturating_add(1);
column = 1;
} else {
column = column.saturating_add(1);
}
}
Self { line, column }
}
}
impl fmt::Display for LineColumn {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}:{}", self.line, self.column)
}
}