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