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