1use std::{
5 cmp,
6 cmp::Ordering,
7 fmt,
8 fmt::{Display, Formatter},
9 ops::Deref,
10 sync::Arc,
11};
12
13use serde::{Deserialize, Serialize};
14
15#[repr(transparent)]
17#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
18pub struct StatementColumn(pub u32);
19
20impl Deref for StatementColumn {
21 type Target = u32;
22
23 fn deref(&self) -> &Self::Target {
24 &self.0
25 }
26}
27
28impl PartialEq<i32> for StatementColumn {
29 fn eq(&self, other: &i32) -> bool {
30 self.0 == *other as u32
31 }
32}
33
34#[repr(transparent)]
35#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
36pub struct StatementLine(pub u32);
37
38impl Deref for StatementLine {
39 type Target = u32;
40
41 fn deref(&self) -> &Self::Target {
42 &self.0
43 }
44}
45
46impl PartialEq<i32> for StatementLine {
47 fn eq(&self, other: &i32) -> bool {
48 self.0 == *other as u32
49 }
50}
51
52#[derive(Debug, Clone, PartialEq, Hash, Serialize, Deserialize, Default)]
54pub enum Fragment {
55 #[default]
57 None,
58
59 Statement {
61 text: Arc<str>,
62 line: StatementLine,
63 column: StatementColumn,
64 },
65
66 Internal {
68 text: Arc<str>,
69 },
70}
71
72impl Fragment {
73 pub fn text(&self) -> &str {
75 match self {
76 Fragment::None => "",
77 Fragment::Statement {
78 text,
79 ..
80 }
81 | Fragment::Internal {
82 text,
83 ..
84 } => text,
85 }
86 }
87
88 pub fn line(&self) -> StatementLine {
90 match self {
91 Fragment::Statement {
92 line,
93 ..
94 } => *line,
95 _ => StatementLine(1),
96 }
97 }
98
99 pub fn column(&self) -> StatementColumn {
101 match self {
102 Fragment::Statement {
103 column,
104 ..
105 } => *column,
106 _ => StatementColumn(0),
107 }
108 }
109
110 pub fn sub_fragment(&self, offset: usize, length: usize) -> Fragment {
113 let text = self.text();
114 let end = cmp::min(offset + length, text.len());
115 let sub_text = if offset < text.len() {
116 &text[offset..end]
117 } else {
118 ""
119 };
120
121 match self {
122 Fragment::None => Fragment::None,
123 Fragment::Statement {
124 line,
125 column,
126 ..
127 } => Fragment::Statement {
128 text: Arc::from(sub_text),
129 line: *line,
130 column: StatementColumn(column.0 + offset as u32),
131 },
132 Fragment::Internal {
133 ..
134 } => Fragment::Internal {
135 text: Arc::from(sub_text),
136 },
137 }
138 }
139
140 pub fn with_text(&self, text: impl Into<String>) -> Fragment {
142 let text = Arc::from(text.into());
143 match self {
144 Fragment::Statement {
145 line,
146 column,
147 ..
148 } => Fragment::Statement {
149 text,
150 line: *line,
151 column: *column,
152 },
153 Fragment::Internal {
154 ..
155 } => Fragment::Internal {
156 text,
157 },
158 Fragment::None => Fragment::Internal {
159 text,
160 },
161 }
162 }
163}
164
165impl Fragment {
166 pub fn internal(text: impl Into<String>) -> Self {
169 Fragment::Internal {
170 text: Arc::from(text.into()),
171 }
172 }
173
174 pub fn testing(text: impl Into<String>) -> Self {
177 Fragment::Statement {
178 text: Arc::from(text.into()),
179 line: StatementLine(1),
180 column: StatementColumn(0),
181 }
182 }
183
184 pub fn testing_empty() -> Self {
186 Self::testing("")
187 }
188
189 pub fn merge_all(fragments: impl IntoIterator<Item = Fragment>) -> Fragment {
192 let mut fragments: Vec<Fragment> = fragments.into_iter().collect();
193 assert!(!fragments.is_empty());
194
195 fragments.sort();
196
197 let first = fragments.first().unwrap();
198
199 let mut text = String::with_capacity(fragments.iter().map(|f| f.text().len()).sum());
200 for fragment in &fragments {
201 text.push_str(fragment.text());
202 }
203
204 match first {
205 Fragment::None => Fragment::None,
206 Fragment::Statement {
207 line,
208 column,
209 ..
210 } => Fragment::Statement {
211 text: Arc::from(text),
212 line: *line,
213 column: *column,
214 },
215 Fragment::Internal {
216 ..
217 } => Fragment::Internal {
218 text: Arc::from(text),
219 },
220 }
221 }
222
223 pub fn fragment(&self) -> &str {
225 self.text()
226 }
227}
228
229impl AsRef<str> for Fragment {
230 fn as_ref(&self) -> &str {
231 self.text()
232 }
233}
234
235impl Display for Fragment {
236 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
237 Display::fmt(self.text(), f)
238 }
239}
240
241impl PartialOrd for Fragment {
242 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
243 Some(self.cmp(other))
244 }
245}
246
247impl Ord for Fragment {
248 fn cmp(&self, other: &Self) -> Ordering {
249 self.column().cmp(&other.column()).then(self.line().cmp(&other.line()))
250 }
251}
252
253impl Eq for Fragment {}
254
255impl From<String> for Fragment {
257 fn from(s: String) -> Self {
258 Fragment::Internal {
259 text: Arc::from(s),
260 }
261 }
262}
263
264impl From<&str> for Fragment {
265 fn from(s: &str) -> Self {
266 Fragment::Internal {
267 text: Arc::from(s),
268 }
269 }
270}
271
272impl Fragment {
273 pub fn statement(text: impl Into<String>, line: u32, column: u32) -> Self {
275 Fragment::Statement {
276 text: Arc::from(text.into()),
277 line: StatementLine(line),
278 column: StatementColumn(column),
279 }
280 }
281
282 pub fn none() -> Self {
284 Fragment::None
285 }
286}
287
288impl PartialEq<str> for Fragment {
290 fn eq(&self, other: &str) -> bool {
291 self.text() == other
292 }
293}
294
295impl PartialEq<&str> for Fragment {
296 fn eq(&self, other: &&str) -> bool {
297 self.text() == *other
298 }
299}
300
301impl PartialEq<String> for Fragment {
302 fn eq(&self, other: &String) -> bool {
303 self.text() == other.as_str()
304 }
305}
306
307impl PartialEq<String> for &Fragment {
308 fn eq(&self, other: &String) -> bool {
309 self.text() == other.as_str()
310 }
311}
312
313pub trait LazyFragment {
315 fn fragment(&self) -> Fragment;
316}
317
318impl<F> LazyFragment for F
319where
320 F: Fn() -> Fragment,
321{
322 fn fragment(&self) -> Fragment {
323 self()
324 }
325}
326
327impl LazyFragment for &Fragment {
328 fn fragment(&self) -> Fragment {
329 (*self).clone()
330 }
331}
332
333impl LazyFragment for Fragment {
334 fn fragment(&self) -> Fragment {
335 self.clone()
336 }
337}