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 AsRef<str>) -> Fragment {
142 let text = Arc::from(text.as_ref());
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 AsRef<str>) -> Self {
173 Fragment::Internal {
174 text: Arc::from(text.as_ref()),
175 }
176 }
177
178 pub fn testing(text: impl AsRef<str>) -> Self {
185 Fragment::Statement {
186 text: Arc::from(text.as_ref()),
187 line: StatementLine(1),
188 column: StatementColumn(0),
189 }
190 }
191
192 pub fn testing_empty() -> Self {
194 Self::testing("")
195 }
196
197 pub fn merge_all(fragments: impl IntoIterator<Item = Fragment>) -> Fragment {
200 let mut fragments: Vec<Fragment> = fragments.into_iter().collect();
201 assert!(!fragments.is_empty());
202
203 fragments.sort();
204
205 let first = fragments.first().unwrap();
206
207 let mut text = String::with_capacity(fragments.iter().map(|f| f.text().len()).sum());
208 for fragment in &fragments {
209 text.push_str(fragment.text());
210 }
211
212 match first {
213 Fragment::None => Fragment::None,
214 Fragment::Statement {
215 line,
216 column,
217 ..
218 } => Fragment::Statement {
219 text: Arc::from(text),
220 line: *line,
221 column: *column,
222 },
223 Fragment::Internal {
224 ..
225 } => Fragment::Internal {
226 text: Arc::from(text),
227 },
228 }
229 }
230
231 pub fn fragment(&self) -> &str {
233 self.text()
234 }
235}
236
237impl AsRef<str> for Fragment {
238 fn as_ref(&self) -> &str {
239 self.text()
240 }
241}
242
243impl Display for Fragment {
244 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
245 Display::fmt(self.text(), f)
246 }
247}
248
249impl PartialOrd for Fragment {
250 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
251 Some(self.cmp(other))
252 }
253}
254
255impl Ord for Fragment {
256 fn cmp(&self, other: &Self) -> Ordering {
257 self.column().cmp(&other.column()).then(self.line().cmp(&other.line()))
258 }
259}
260
261impl Eq for Fragment {}
262
263impl From<String> for Fragment {
265 fn from(s: String) -> Self {
266 Fragment::Internal {
267 text: Arc::from(s),
268 }
269 }
270}
271
272impl From<&str> for Fragment {
273 fn from(s: &str) -> Self {
274 Fragment::Internal {
275 text: Arc::from(s),
276 }
277 }
278}
279
280impl Fragment {
281 pub fn statement(text: impl AsRef<str>, line: u32, column: u32) -> Self {
283 Fragment::Statement {
284 text: Arc::from(text.as_ref()),
285 line: StatementLine(line),
286 column: StatementColumn(column),
287 }
288 }
289
290 pub fn none() -> Self {
292 Fragment::None
293 }
294}
295
296impl PartialEq<str> for Fragment {
298 fn eq(&self, other: &str) -> bool {
299 self.text() == other
300 }
301}
302
303impl PartialEq<&str> for Fragment {
304 fn eq(&self, other: &&str) -> bool {
305 self.text() == *other
306 }
307}
308
309impl PartialEq<String> for Fragment {
310 fn eq(&self, other: &String) -> bool {
311 self.text() == other.as_str()
312 }
313}
314
315impl PartialEq<String> for &Fragment {
316 fn eq(&self, other: &String) -> bool {
317 self.text() == other.as_str()
318 }
319}
320
321pub trait LazyFragment {
323 fn fragment(&self) -> Fragment;
324}
325
326impl<F> LazyFragment for F
327where
328 F: Fn() -> Fragment,
329{
330 fn fragment(&self) -> Fragment {
331 self()
332 }
333}
334
335impl LazyFragment for &Fragment {
336 fn fragment(&self) -> Fragment {
337 (*self).clone()
338 }
339}
340
341impl LazyFragment for Fragment {
342 fn fragment(&self) -> Fragment {
343 self.clone()
344 }
345}