use std::fmt;
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct Loc {
pub line: usize,
pub column: usize,
}
impl Loc {
pub fn new(line: usize, column: usize) -> Self {
Self { line, column }
}
pub fn with_column_offset(&self, offset: usize) -> Loc {
Self {
line: self.line,
column: self.column + offset,
}
}
pub fn span_to(&self, end: Self) -> Span {
Span::new(*self, end)
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Span {
pub begin: Loc,
pub end: Loc,
}
impl Span {
pub fn new(begin: Loc, end: Loc) -> Self {
debug_assert!(
begin.line < end.line || (begin.line == end.line && begin.column < end.column)
);
Self { begin, end }
}
}
impl fmt::Display for Span {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.begin.line == self.end.line {
if self.begin.column + 1 == self.end.column {
write!(f, "{}:{}", self.begin.line + 1, self.begin.column + 1)
} else {
write!(
f,
"{}:{}-{}",
self.begin.line + 1,
self.begin.column + 1,
self.end.column
)
}
} else {
write!(
f,
"{}:{}-{}:{}",
self.begin.line + 1,
self.begin.column + 1,
self.end.line + 1,
self.end.column
)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_span_display() {
let span = Span::new(Loc::new(0, 1), Loc::new(0, 2));
assert_eq!(format!("{}", span), "1:2");
let span = Span::new(Loc::new(0, 1), Loc::new(0, 3));
assert_eq!(format!("{}", span), "1:2-3");
let span = Span::new(Loc::new(0, 9), Loc::new(2, 3));
assert_eq!(format!("{}", span), "1:10-3:3");
}
}