1#[derive(Debug, Clone, Copy, PartialEq, Eq)]
3pub struct Span {
4 pub start: usize,
5 pub end: usize,
6}
7
8impl Span {
9 pub fn new(start: usize, end: usize) -> Self {
10 Self { start, end }
11 }
12
13 pub fn join(self, other: Span) -> Span {
14 Span::new(self.start.min(other.start), self.end.max(other.end))
15 }
16}
17
18#[derive(Debug, Clone, PartialEq, Eq)]
19pub struct Spanned<T> {
20 pub value: T,
21 pub span: Span,
22}
23
24impl<T> Spanned<T> {
25 pub fn new(value: T, span: Span) -> Self {
26 Self { value, span }
27 }
28}
29
30#[derive(Debug, Clone, Copy, PartialEq, Eq)]
32pub struct LineCol {
33 pub line: usize,
34 pub col: usize,
35}
36
37pub struct LineIndex {
39 line_starts: Vec<usize>,
40}
41
42impl LineIndex {
43 pub fn new(src: &str) -> Self {
44 let mut line_starts = vec![0];
45 line_starts.extend(src.match_indices('\n').map(|(i, _)| i + 1));
46 Self { line_starts }
47 }
48
49 pub fn line_col(&self, offset: usize) -> LineCol {
50 let line = self.line_starts.partition_point(|&s| s <= offset).max(1) - 1;
51 LineCol {
52 line: line + 1,
53 col: offset - self.line_starts[line] + 1,
54 }
55 }
56
57 pub fn line_text<'a>(&self, src: &'a str, line: usize) -> &'a str {
58 let start = self.line_starts[line - 1];
59 let end = self
60 .line_starts
61 .get(line)
62 .map(|&s| s.saturating_sub(1))
63 .unwrap_or(src.len());
64 src[start..end].trim_end_matches('\r')
65 }
66}