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