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