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<String>,
59 line: StatementLine,
60 column: StatementColumn,
61 },
62
63 Internal {
65 text: Arc<String>,
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.to_string()),
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.to_string()),
133 },
134 }
135 }
136}
137
138impl Fragment {
139 pub fn internal(text: impl Into<String>) -> Self {
142 Fragment::Internal {
143 text: Arc::from(text.into()),
144 }
145 }
146
147 pub fn testing(text: impl Into<String>) -> Self {
150 Fragment::Statement {
151 text: Arc::from(text.into()),
152 line: StatementLine(1),
153 column: StatementColumn(0),
154 }
155 }
156
157 pub fn testing_empty() -> Self {
159 Self::testing("")
160 }
161
162 pub fn merge_all(fragments: impl IntoIterator<Item = Fragment>) -> Fragment {
165 let mut fragments: Vec<Fragment> = fragments.into_iter().collect();
166 assert!(!fragments.is_empty());
167
168 fragments.sort();
169
170 let first = fragments.first().unwrap();
171
172 let mut text = String::with_capacity(fragments.iter().map(|f| f.text().len()).sum());
173 for fragment in &fragments {
174 text.push_str(fragment.text());
175 }
176
177 match first {
178 Fragment::None => Fragment::None,
179 Fragment::Statement {
180 line,
181 column,
182 ..
183 } => Fragment::Statement {
184 text: Arc::from(text),
185 line: *line,
186 column: *column,
187 },
188 Fragment::Internal {
189 ..
190 } => Fragment::Internal {
191 text: Arc::from(text),
192 },
193 }
194 }
195
196 pub fn fragment(&self) -> &str {
198 self.text()
199 }
200}
201
202impl Default for Fragment {
203 fn default() -> Self {
204 Fragment::None
205 }
206}
207
208impl AsRef<str> for Fragment {
209 fn as_ref(&self) -> &str {
210 self.text()
211 }
212}
213
214impl Display for Fragment {
215 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
216 Display::fmt(self.text(), f)
217 }
218}
219
220impl PartialOrd for Fragment {
221 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
222 Some(self.cmp(other))
223 }
224}
225
226impl Ord for Fragment {
227 fn cmp(&self, other: &Self) -> Ordering {
228 self.column().cmp(&other.column()).then(self.line().cmp(&other.line()))
229 }
230}
231
232impl Eq for Fragment {}
233
234impl From<String> for Fragment {
236 fn from(s: String) -> Self {
237 Fragment::Internal {
238 text: Arc::from(s),
239 }
240 }
241}
242
243impl From<&str> for Fragment {
244 fn from(s: &str) -> Self {
245 Fragment::Internal {
246 text: Arc::from(s.to_string()),
247 }
248 }
249}
250
251impl Fragment {
252 pub fn statement(text: impl Into<String>, line: u32, column: u32) -> Self {
254 Fragment::Statement {
255 text: Arc::from(text.into()),
256 line: StatementLine(line),
257 column: StatementColumn(column),
258 }
259 }
260
261 pub fn none() -> Self {
263 Fragment::None
264 }
265}
266
267impl PartialEq<str> for Fragment {
269 fn eq(&self, other: &str) -> bool {
270 self.text() == other
271 }
272}
273
274impl PartialEq<&str> for Fragment {
275 fn eq(&self, other: &&str) -> bool {
276 self.text() == *other
277 }
278}
279
280impl PartialEq<String> for Fragment {
281 fn eq(&self, other: &String) -> bool {
282 self.text() == other.as_str()
283 }
284}
285
286impl PartialEq<String> for &Fragment {
287 fn eq(&self, other: &String) -> bool {
288 self.text() == other.as_str()
289 }
290}
291
292pub trait LazyFragment {
294 fn fragment(&self) -> Fragment;
295}
296
297impl<F> LazyFragment for F
298where
299 F: Fn() -> Fragment,
300{
301 fn fragment(&self) -> Fragment {
302 self()
303 }
304}
305
306impl LazyFragment for &Fragment {
307 fn fragment(&self) -> Fragment {
308 (*self).clone()
309 }
310}
311
312impl LazyFragment for Fragment {
313 fn fragment(&self) -> Fragment {
314 self.clone()
315 }
316}