acdc_parser/model/
location.rs1use serde::{
2 Serialize,
3 ser::{SerializeSeq, Serializer},
4};
5
6#[derive(Debug, Clone, Default, PartialEq)]
12pub(crate) struct LeveloffsetRange {
13 pub(crate) start_offset: usize,
15 pub(crate) end_offset: usize,
17 pub(crate) value: isize,
19}
20
21impl LeveloffsetRange {
22 #[must_use]
24 pub(crate) fn new(start_offset: usize, end_offset: usize, value: isize) -> Self {
25 Self {
26 start_offset,
27 end_offset,
28 value,
29 }
30 }
31
32 #[must_use]
34 pub(crate) fn contains(&self, byte_offset: usize) -> bool {
35 byte_offset >= self.start_offset && byte_offset < self.end_offset
36 }
37}
38
39#[must_use]
44pub(crate) fn calculate_leveloffset_at(ranges: &[LeveloffsetRange], byte_offset: usize) -> isize {
45 ranges
46 .iter()
47 .filter_map(|r| {
48 if r.contains(byte_offset) {
49 Some(r.value)
50 } else {
51 None
52 }
53 })
54 .sum()
55}
56
57#[derive(Debug, Clone, PartialEq)]
63pub(crate) struct SourceRange {
64 pub(crate) start_offset: usize,
66 pub(crate) end_offset: usize,
68 pub(crate) file: std::path::PathBuf,
70 pub(crate) start_line: usize,
72}
73
74impl SourceRange {
75 #[must_use]
77 pub(crate) fn contains(&self, byte_offset: usize) -> bool {
78 byte_offset >= self.start_offset && byte_offset < self.end_offset
79 }
80}
81
82pub(crate) trait Locateable {
83 fn location(&self) -> &Location;
85}
86
87#[derive(Debug, Default, Clone, Hash, Eq, PartialEq)]
89#[non_exhaustive]
90pub struct Location {
91 pub absolute_start: usize,
93 pub absolute_end: usize,
95
96 pub start: Position,
98 pub end: Position,
100}
101
102impl Location {
103 pub fn validate(&self, input: &str) -> Result<(), String> {
113 if self.absolute_start > self.absolute_end {
115 return Err(format!(
116 "Invalid range: start {} > end {}",
117 self.absolute_start, self.absolute_end
118 ));
119 }
120
121 if self.absolute_end > input.len() {
123 return Err(format!(
124 "End offset {} exceeds input length {}",
125 self.absolute_end,
126 input.len()
127 ));
128 }
129
130 if !input.is_char_boundary(self.absolute_start) {
132 return Err(format!(
133 "Start offset {} not on UTF-8 boundary",
134 self.absolute_start
135 ));
136 }
137
138 if !input.is_char_boundary(self.absolute_end) {
139 return Err(format!(
140 "End offset {} not on UTF-8 boundary",
141 self.absolute_end
142 ));
143 }
144
145 Ok(())
146 }
147
148 pub fn shift(&mut self, parent: Option<&Location>) {
153 if let Some(parent) = parent {
154 if parent.start.line == 0 {
155 return;
156 }
157 self.absolute_start += parent.absolute_start;
158 self.absolute_end += parent.absolute_start;
159 self.start.line += parent.start.line;
160 self.end.line += parent.start.line;
161 }
162 }
163
164 pub fn shift_inline(&mut self, parent: Option<&Location>) {
168 if let Some(parent) = parent {
169 if parent.start.line != 0 || parent.start.column != 0 {
170 self.absolute_start += parent.absolute_start;
171 self.absolute_end += parent.absolute_start;
172 }
173 if parent.start.line != 0 {
174 self.start.line += parent.start.line - 1;
175 self.end.line += parent.start.line - 1;
176 }
177 if parent.start.column != 0 {
178 self.start.column += parent.start.column - 1;
179 self.end.column += parent.start.column - 1;
180 }
181 }
182 }
183
184 pub fn shift_line_column(&mut self, line: usize, column: usize) {
185 self.start.line += line - 1;
186 self.end.line += line - 1;
187 self.start.column += column - 1;
188 self.end.column += column - 1;
189 }
190}
191
192impl Serialize for Location {
198 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
199 where
200 S: Serializer,
201 {
202 let mut state = serializer.serialize_seq(Some(4))?;
203 state.serialize_element(&self.start)?;
204 state.serialize_element(&self.end)?;
205 state.end()
206 }
207}
208
209impl std::fmt::Display for Location {
210 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
211 write!(
212 f,
213 "location.start({}), location.end({})",
214 self.start, self.end
215 )
216 }
217}
218
219#[derive(Debug, Default, Clone, Hash, Eq, PartialEq, Serialize)]
224#[non_exhaustive]
225pub struct Position {
226 pub line: usize,
228 #[serde(rename = "col")]
230 pub column: usize,
231}
232
233impl std::fmt::Display for Position {
234 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
235 write!(f, "line: {}, column: {}", self.line, self.column)
236 }
237}