textparse/
span.rs

1pub use textparse_derive::Span;
2
3/// Position (offset) in a text.
4#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
5pub struct Position(usize);
6
7impl Position {
8    /// Makes a new [`Position`] instance.
9    pub const fn new(offset: usize) -> Self {
10        Self(offset)
11    }
12
13    /// Gets the offset.
14    pub const fn get(self) -> usize {
15        self.0
16    }
17
18    /// Returns the line and column numbers at where this position is located in the given text.
19    pub fn line_and_column(self, text: &str) -> (usize, usize) {
20        let mut line = 1;
21        let mut column = 1;
22        for c in text[..self.0].chars() {
23            if c == '\n' {
24                line += 1;
25                column = 1;
26            } else {
27                column += 1;
28            }
29        }
30        (line, column)
31    }
32}
33
34/// This trait allows for representing a parsed item that has start and end positions in a text.
35pub trait Span {
36    /// Returns the start position of this item.
37    fn start_position(&self) -> Position;
38
39    /// Returns the end position of this item.
40    fn end_position(&self) -> Position;
41
42    /// Returns `true` if the span is empty, otherwise `false`.
43    fn is_empty(&self) -> bool {
44        self.start_position().get() >= self.end_position().get()
45    }
46
47    /// Returns the length of this span.
48    fn len(&self) -> usize {
49        if self.is_empty() {
50            0
51        } else {
52            self.end_position().get() - self.start_position().get()
53        }
54    }
55
56    /// Returns the text representation of this item.
57    fn text<'a>(&self, text: &'a str) -> &'a str {
58        &text[self.start_position().get()..self.end_position().get()]
59    }
60}
61
62impl Span for Position {
63    fn start_position(&self) -> Position {
64        *self
65    }
66
67    fn end_position(&self) -> Position {
68        *self
69    }
70}
71
72impl Span for std::ops::Range<Position> {
73    fn start_position(&self) -> Position {
74        self.start
75    }
76
77    fn end_position(&self) -> Position {
78        self.end
79    }
80}
81
82impl<T: Span> Span for Box<T> {
83    fn start_position(&self) -> Position {
84        (**self).start_position()
85    }
86
87    fn end_position(&self) -> Position {
88        (**self).end_position()
89    }
90}
91
92impl<T: Span> Span for &T {
93    fn start_position(&self) -> Position {
94        (**self).start_position()
95    }
96
97    fn end_position(&self) -> Position {
98        (**self).end_position()
99    }
100}
101
102impl<T0: Span, T1: Span> Span for (T0, T1) {
103    fn start_position(&self) -> Position {
104        self.0.start_position()
105    }
106
107    fn end_position(&self) -> Position {
108        self.1.end_position()
109    }
110}
111
112impl<T0: Span, T1: Span, T2: Span> Span for (T0, T1, T2) {
113    fn start_position(&self) -> Position {
114        self.0.start_position()
115    }
116
117    fn end_position(&self) -> Position {
118        self.2.end_position()
119    }
120}
121
122impl<T0: Span, T1: Span, T2: Span, T3: Span> Span for (T0, T1, T2, T3) {
123    fn start_position(&self) -> Position {
124        self.0.start_position()
125    }
126
127    fn end_position(&self) -> Position {
128        self.3.end_position()
129    }
130}
131
132impl<T0: Span, T1: Span, T2: Span, T3: Span, T4: Span> Span for (T0, T1, T2, T3, T4) {
133    fn start_position(&self) -> Position {
134        self.0.start_position()
135    }
136
137    fn end_position(&self) -> Position {
138        self.4.end_position()
139    }
140}
141
142impl<T0: Span, T1: Span, T2: Span, T3: Span, T4: Span, T5: Span> Span for (T0, T1, T2, T3, T4, T5) {
143    fn start_position(&self) -> Position {
144        self.0.start_position()
145    }
146
147    fn end_position(&self) -> Position {
148        self.5.end_position()
149    }
150}