surrealdb_core/syn/error/
location.rs1use crate::syn::token::Span;
2use std::ops::Range;
3
4#[derive(Clone, Copy, Debug)]
8#[non_exhaustive]
9pub struct Location {
10 pub line: usize,
11 pub column: usize,
13}
14
15unsafe fn str_offset(a: &str, b: &str) -> usize {
17 b.as_ptr().offset_from(a.as_ptr()) as usize
18}
19
20impl Location {
21 fn range_of_source_end(source: &str) -> Range<Self> {
22 let (line, column) = source
23 .lines()
24 .enumerate()
25 .last()
26 .map(|(idx, line)| {
27 let idx = idx + 1;
28 let line_idx = line.chars().count().max(1);
29 (idx, line_idx)
30 })
31 .unwrap_or((1, 1));
32
33 Self {
34 line,
35 column,
36 }..Self {
37 line,
38 column: column + 1,
39 }
40 }
41 pub fn range_of_span(source: &str, span: Span) -> Range<Self> {
42 if source.len() <= span.offset as usize {
43 return Self::range_of_source_end(source);
44 }
45
46 let mut prev_line = "";
47 let mut lines = source.lines().enumerate().peekable();
48 let start_offset = span.offset as usize;
50 let start = loop {
51 let Some((line_idx, line)) = lines.peek().copied() else {
52 return Self::range_of_source_end(source);
54 };
55 let line_offset = unsafe { str_offset(source, line) };
58
59 if start_offset < line_offset {
60 let len = prev_line.chars().count();
62 break Self {
63 line: line_idx,
64 column: len + 1,
65 };
66 }
67
68 if (line_offset..(line_offset + line.len())).contains(&start_offset) {
69 let column_offset = start_offset - line_offset;
70 let column = line
71 .char_indices()
72 .enumerate()
73 .find(|(_, (char_idx, _))| *char_idx >= column_offset)
74 .map(|(l, _)| l)
75 .unwrap_or_else(|| {
76 line.chars().count()
78 });
79 break Self {
80 line: line_idx + 1,
81 column: column + 1,
82 };
83 }
84
85 lines.next();
86 prev_line = line;
87 };
88
89 let end_offset = span.offset as usize + span.len as usize;
90 let end = loop {
91 let Some((line_idx, line)) = lines.peek().copied() else {
92 break Self::range_of_source_end(source).end;
94 };
95 let line_offset = unsafe { str_offset(source, line) };
98
99 if end_offset < line_offset {
100 let len = prev_line.chars().count();
102 break Self {
103 line: line_idx,
104 column: len + 1,
105 };
106 }
107
108 if (line_offset..(line_offset + line.len())).contains(&end_offset) {
109 let column_offset = end_offset - line_offset;
110 let column = line
111 .char_indices()
112 .enumerate()
113 .find(|(_, (char_idx, _))| *char_idx >= column_offset)
114 .map(|(l, _)| l)
115 .unwrap_or_else(|| {
116 line.chars().count()
118 });
119 break Self {
120 line: line_idx + 1,
121 column: column + 1,
122 };
123 }
124
125 lines.next();
126 prev_line = line;
127 };
128
129 start..end
130 }
131}