1mod delim;
2pub(crate) mod fallback;
3mod range;
4
5#[doc(inline)]
6pub use delim::*;
7#[doc(inline)]
8pub use range::*;
9
10use crate::source::Location;
11
12pub trait Spanner {
13 fn span(&self) -> Span;
14}
15
16#[derive(Debug, Copy, Clone)]
17pub enum Span {
18 Compiler(proc_macro::Span),
19 Fallback(fallback::Span),
20}
21
22impl Span {
23 #[inline]
24 pub fn call_site() -> Self {
25 if proc_macro::is_available() {
26 Self::Compiler(proc_macro::Span::call_site())
27 } else {
28 Self::Fallback(fallback::Span::call_site())
29 }
30 }
31
32 #[inline]
33 pub fn mixed_site() -> Self {
34 if proc_macro::is_available() {
35 Self::Compiler(proc_macro::Span::mixed_site())
36 } else {
37 Self::Fallback(fallback::Span::mixed_site())
38 }
39 }
40
41 #[inline]
42 pub fn def_site() -> Self {
43 #[cfg(nightly)]
44 if proc_macro::is_available() {
45 return Self::Compiler(proc_macro::Span::def_site());
46 }
47
48 Self::Fallback(fallback::Span::def_site())
49 }
50
51 pub fn start(&self) -> Location {
52 match self {
53 Self::Compiler(v) => {
54 let lc = v.start();
55
56 #[cfg(nightly)]
57 {
58 Location::new(v.byte_range().start, lc.line(), lc.column())
59 }
60
61 #[cfg(not(nightly))]
62 {
63 Location::new(0, lc.line(), lc.column())
64 }
65 }
66 Self::Fallback(v) => v.start(),
67 }
68 }
69
70 pub fn end(&self) -> Location {
71 match self {
72 Self::Compiler(v) => {
73 let lc = v.end();
74
75 #[cfg(nightly)]
76 {
77 Location::new(v.byte_range().end, lc.line(), lc.column())
78 }
79
80 #[cfg(not(nightly))]
81 {
82 let src = v.source_text().unwrap_or_default();
83 let index = line_column_offset(&src, v.line(), v.column());
84 Location::new(index, lc.line(), lc.column())
85 }
86 }
87 Self::Fallback(v) => v.end(),
88 }
89 }
90
91 pub fn byte_range(&self) -> std::ops::Range<usize> {
92 match self {
93 #[allow(unused)]
94 Self::Compiler(v) => {
95 #[cfg(nightly)]
96 {
97 v.byte_range()
98 }
99
100 #[cfg(not(nightly))]
101 {
102 let start = v.start();
103 let end = v.end();
104 let src = v.source_text().unwrap_or_default();
105 let start = line_column_offset(&src, start.line(), start.column());
106 let end = line_column_offset(&src, end.line(), end.column());
107 start..end
108 }
109 }
110 Self::Fallback(v) => v.byte_range(),
111 }
112 }
113
114 #[inline]
115 pub fn len(&self) -> usize {
116 match self {
117 Self::Compiler(_) => 0,
118 Self::Fallback(v) => v.len(),
119 }
120 }
121
122 #[inline]
123 pub fn is_empty(&self) -> bool {
124 match self {
125 Self::Compiler(_) => true,
126 Self::Fallback(v) => v.is_empty(),
127 }
128 }
129
130 #[inline]
131 pub fn contains(&self, i: usize) -> bool {
132 match self {
133 Self::Compiler(_) => false,
134 Self::Fallback(v) => v.contains(i),
135 }
136 }
137
138 #[inline]
139 pub fn is_subset(&self, other: &Self) -> bool {
140 match (self, other) {
141 (Self::Fallback(a), Self::Fallback(b)) => a.is_subset(b),
142 _ => false,
143 }
144 }
145
146 #[inline]
147 pub fn join(&self, other: Self) -> Self {
148 #[cfg(nightly)]
149 if let (Self::Compiler(a), Self::Compiler(b)) = (self, other) {
150 if let Some(joined) = a.join(b) {
151 return Self::Compiler(joined);
152 }
153 }
154
155 if let (Self::Fallback(a), Self::Fallback(b)) = (self, other) {
156 return Self::Fallback(a.join(b));
157 }
158
159 other
160 }
161
162 #[inline]
166 pub fn split(self, at: usize) -> (Span, Span) {
167 match self {
168 Self::Fallback(s) => {
169 let range = s.byte_range();
170 let mid = (range.start + at) as u32;
171 let head = fallback::Span::new(range.start as u32, mid);
172 let rest = fallback::Span::new(mid, range.end as u32);
173 (Span::Fallback(head), Span::Fallback(rest))
174 }
175 other => (other, other),
176 }
177 }
178}
179
180impl Default for Span {
181 #[inline]
182 fn default() -> Self {
183 Self::call_site()
184 }
185}
186
187impl Eq for Span {}
188
189impl PartialEq for Span {
190 fn eq(&self, other: &Self) -> bool {
191 match (self, other) {
192 (Self::Compiler(a), Self::Compiler(b)) => {
193 a.start().line() == b.start().line()
194 && a.start().column() == b.start().column()
195 && a.end().line() == b.end().line()
196 && a.end().column() == b.end().column()
197 }
198 (Self::Fallback(a), Self::Fallback(b)) => a == b,
199 _ => false,
200 }
201 }
202}
203
204impl Ord for Span {
205 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
206 match (self, other) {
207 (Self::Compiler(a), Self::Compiler(b)) => match a.start().line().cmp(&b.start().line()) {
208 std::cmp::Ordering::Equal => match a.start().column().cmp(&b.start().column()) {
209 std::cmp::Ordering::Equal => match a.end().line().cmp(&b.end().line()) {
210 std::cmp::Ordering::Equal => a.end().column().cmp(&b.end().column()),
211 ord => ord,
212 },
213 ord => ord,
214 },
215 ord => ord,
216 },
217 (Self::Fallback(a), Self::Fallback(b)) => a.cmp(b),
218 (Self::Fallback(_), Self::Compiler(_)) => std::cmp::Ordering::Less,
219 (Self::Compiler(_), Self::Fallback(_)) => std::cmp::Ordering::Greater,
220 }
221 }
222}
223
224impl PartialOrd for Span {
225 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
226 Some(self.cmp(other))
227 }
228}
229
230impl std::hash::Hash for Span {
231 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
232 match self {
233 #[allow(unused)]
234 Self::Compiler(s) => {
235 #[cfg(nightly)]
236 {
237 let range = s.byte_range();
238 range.start.hash(state);
239 range.end.hash(state);
240 }
241
242 #[cfg(not(nightly))]
243 {
244 let start = s.start();
245 let end = s.end();
246 let src = s.source_text().unwrap_or_default();
247
248 line_column_offset(&src, start.line(), start.column()).hash(state);
249 line_column_offset(&src, end.line(), end.column()).hash(state);
250 }
251 }
252 Self::Fallback(s) => s.hash(state),
253 }
254 }
255}
256
257impl From<fallback::Span> for Span {
258 #[inline]
259 fn from(value: fallback::Span) -> Self {
260 Self::Fallback(value)
261 }
262}
263
264#[cfg(feature = "serde")]
265impl serde::Serialize for Span {
266 fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
267 where
268 S: serde::Serializer,
269 {
270 use serde::ser::SerializeStruct;
271
272 match self {
273 Self::Fallback(v) => v.serialize(s),
274 #[allow(unused)]
275 Self::Compiler(v) => {
276 let mut o = s.serialize_struct("Span", 2)?;
277
278 #[cfg(nightly)]
279 {
280 o.serialize_field("start", &v.byte_range().start)?;
281 o.serialize_field("end", &v.byte_range().end)?;
282 }
283
284 #[cfg(not(nightly))]
285 {
286 let start = v.start();
287 let end = v.end();
288 let src = v.source_text().unwrap_or_default();
289
290 o.serialize_field("start", &line_column_offset(&src, start.line(), start.column()))?;
291 o.serialize_field("end", &line_column_offset(&src, end.line(), end.column()))?;
292 }
293
294 o.end()
295 }
296 }
297 }
298}
299
300pub fn line_column_offset(src: &str, ln: usize, col: usize) -> usize {
301 let mut curr = 0;
302
303 for (i, line) in src.lines().enumerate() {
304 if i + 1 == ln {
305 let offset = line.char_indices().nth(col).map(|(i, _)| i).unwrap_or(line.len());
306 return curr + offset;
307 }
308
309 curr += line.len() + 1;
310 }
311
312 0
313}