Skip to main content

reifydb_type/
fragment.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2025 ReifyDB
3
4use 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}