reifydb_type/fragment/
mod.rs

1// Copyright (c) reifydb.com 2025
2// This file is licensed under the MIT, see license.md file
3
4pub mod borrowed;
5pub mod owned;
6
7use std::ops::Deref;
8
9pub use borrowed::BorrowedFragment;
10pub use owned::OwnedFragment;
11use serde::{Deserialize, Serialize};
12
13// Position types for fragments
14#[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/// Core enum for fragment types
51#[derive(Debug, Clone)]
52pub enum Fragment<'a> {
53	Owned(OwnedFragment),
54	Borrowed(BorrowedFragment<'a>),
55	None,
56}
57
58impl PartialEq<str> for Fragment<'_> {
59	fn eq(&self, other: &str) -> bool {
60		self.text() == other
61	}
62}
63
64impl PartialEq<&str> for Fragment<'_> {
65	fn eq(&self, other: &&str) -> bool {
66		self.text() == *other
67	}
68}
69
70impl PartialEq<String> for Fragment<'_> {
71	fn eq(&self, other: &String) -> bool {
72		self.text() == other.as_str()
73	}
74}
75
76impl PartialEq<String> for &Fragment<'_> {
77	fn eq(&self, other: &String) -> bool {
78		self.text() == other.as_str()
79	}
80}
81
82impl Fragment<'_> {
83	pub fn owned_internal(text: impl Into<String>) -> Self {
84		Fragment::Owned(OwnedFragment::Internal {
85			text: text.into(),
86		})
87	}
88
89	pub fn owned_empty() -> Self {
90		Fragment::Owned(OwnedFragment::testing_empty())
91	}
92
93	pub fn borrowed_internal(text: &str) -> Fragment<'_> {
94		Fragment::Borrowed(BorrowedFragment::Internal {
95			text,
96		})
97	}
98
99	pub fn none() -> Self {
100		Self::None
101	}
102
103	pub fn testing_empty() -> Fragment<'static> {
104		Fragment::Borrowed(BorrowedFragment::Internal {
105			text: "",
106		})
107	}
108}
109
110impl<'a> Fragment<'a> {
111	/// Get the text value of the fragment
112	pub fn text(&self) -> &str {
113		match self {
114			Fragment::Owned(f) => f.text(),
115			Fragment::Borrowed(f) => f.text(),
116			Fragment::None => "",
117		}
118	}
119
120	/// Get line position
121	pub fn line(&self) -> StatementLine {
122		match self {
123			Fragment::Owned(f) => f.line(),
124			Fragment::Borrowed(f) => f.line(),
125			Fragment::None => StatementLine(1),
126		}
127	}
128
129	/// Get column position
130	pub fn column(&self) -> StatementColumn {
131		match self {
132			Fragment::Owned(f) => f.column(),
133			Fragment::Borrowed(f) => f.column(),
134			Fragment::None => StatementColumn(0),
135		}
136	}
137
138	/// Convert to owned variant
139	pub fn into_owned(self) -> OwnedFragment {
140		match self {
141			Fragment::Owned(f) => f,
142			Fragment::Borrowed(f) => f.into_owned(),
143			Fragment::None => OwnedFragment::None,
144		}
145	}
146
147	/// Convert to owned Fragment with 'static lifetime while preserving location info
148	pub fn to_static(self) -> Fragment<'static> {
149		Fragment::Owned(self.into_owned())
150	}
151
152	/// Create a borrowed view of this fragment
153	pub fn as_borrowed(&'a self) -> Fragment<'a> {
154		match self {
155			Fragment::Owned(owned) => match owned {
156				OwnedFragment::None => Fragment::None,
157				OwnedFragment::Statement {
158					text,
159					line,
160					column,
161				} => Fragment::Borrowed(BorrowedFragment::Statement {
162					text: text.as_str(),
163					line: *line,
164					column: *column,
165				}),
166				OwnedFragment::Internal {
167					text,
168				} => Fragment::Borrowed(BorrowedFragment::Internal {
169					text: text.as_str(),
170				}),
171			},
172			Fragment::Borrowed(b) => Fragment::Borrowed(*b),
173			Fragment::None => Fragment::None,
174		}
175	}
176
177	/// Get a sub-fragment starting at the given offset with the given
178	/// length
179	pub fn sub_fragment(&self, offset: usize, length: usize) -> OwnedFragment {
180		match self {
181			Fragment::Owned(f) => f.sub_fragment(offset, length),
182			Fragment::Borrowed(f) => f.sub_fragment(offset, length),
183			Fragment::None => OwnedFragment::None,
184		}
185	}
186
187	/// Merge multiple fragments (in any order) into one encompassing
188	/// fragment
189	pub fn merge_all(fragments: impl IntoIterator<Item = Fragment<'a>>) -> Fragment<'a> {
190		let owned_fragments: Vec<OwnedFragment> = fragments.into_iter().map(|f| f.into_owned()).collect();
191		Fragment::Owned(OwnedFragment::merge_all(owned_fragments))
192	}
193}
194
195/// Trait for types that can be converted into a Fragment
196pub trait IntoFragment<'a> {
197	fn into_fragment(self) -> Fragment<'a>;
198}
199
200// Additional IntoFragment implementations for closure returning OwnedFragment
201impl<F> IntoFragment<'static> for F
202where
203	F: Fn() -> OwnedFragment,
204{
205	fn into_fragment(self) -> Fragment<'static> {
206		Fragment::Owned(self())
207	}
208}
209
210// Implementation for &OwnedFragment
211impl IntoFragment<'static> for &OwnedFragment {
212	fn into_fragment(self) -> Fragment<'static> {
213		Fragment::Owned(self.clone())
214	}
215}
216
217/// Trait for lazy fragment generation that returns Fragment instead of
218/// OwnedFragment
219pub trait LazyFragment<'a>: Copy {
220	fn fragment(&self) -> Fragment<'a>;
221}
222
223// Implementation for closures that return Fragment
224impl<'a, F> LazyFragment<'a> for F
225where
226	F: Fn() -> Fragment<'a> + Copy,
227{
228	fn fragment(&self) -> Fragment<'a> {
229		self()
230	}
231}
232
233// Implementation for Fragment itself - using clone since we can't borrow with
234// proper lifetime
235impl<'a> LazyFragment<'a> for Fragment<'a>
236where
237	Fragment<'a>: Copy,
238{
239	fn fragment(&self) -> Fragment<'a> {
240		self.clone()
241	}
242}
243
244// Implementation for &Fragment
245impl<'a, 'b> LazyFragment<'a> for &'b Fragment<'a>
246where
247	'a: 'b,
248{
249	fn fragment(&self) -> Fragment<'a> {
250		(*self).clone()
251	}
252}
253
254// Implementation for Fragment enum
255impl<'a> IntoFragment<'a> for Fragment<'a> {
256	fn into_fragment(self) -> Fragment<'a> {
257		self
258	}
259}
260
261// Implementation for &Fragment - creates a borrowed view
262impl<'a> IntoFragment<'a> for &'a Fragment<'a> {
263	fn into_fragment(self) -> Fragment<'a> {
264		self.as_borrowed()
265	}
266}
267
268// Implementation for OwnedFragment
269impl IntoFragment<'_> for OwnedFragment {
270	fn into_fragment(self) -> Fragment<'static> {
271		Fragment::Owned(self)
272	}
273}
274
275// Implementation for BorrowedFragment - converts to owned
276impl<'a> IntoFragment<'a> for BorrowedFragment<'a> {
277	fn into_fragment(self) -> Fragment<'a> {
278		Fragment::Owned(self.into_owned())
279	}
280}
281
282// Implementation for Option<OwnedFragment>
283impl IntoFragment<'_> for Option<OwnedFragment> {
284	fn into_fragment(self) -> Fragment<'static> {
285		match self {
286			Some(fragment) => Fragment::Owned(fragment),
287			None => Fragment::None,
288		}
289	}
290}
291
292// Also provide From implementations for convenience
293impl From<Option<OwnedFragment>> for OwnedFragment {
294	fn from(fragment_opt: Option<OwnedFragment>) -> Self {
295		fragment_opt.unwrap_or_else(|| OwnedFragment::None)
296	}
297}
298
299// From<&str> implementation - creates borrowed internal fragment
300impl<'a> From<&'a str> for Fragment<'a> {
301	fn from(s: &'a str) -> Self {
302		Fragment::Borrowed(BorrowedFragment::Internal {
303			text: s,
304		})
305	}
306}
307
308// From<String> implementation - creates owned internal fragment
309impl From<String> for Fragment<'static> {
310	fn from(s: String) -> Self {
311		Fragment::Owned(OwnedFragment::Internal {
312			text: s,
313		})
314	}
315}
316
317// String reference implementations - return borrowed fragments to avoid
318// allocation
319impl<'a> IntoFragment<'a> for &'a str {
320	fn into_fragment(self) -> Fragment<'a> {
321		Fragment::Borrowed(BorrowedFragment::Internal {
322			text: self,
323		})
324	}
325}
326
327impl<'a> IntoFragment<'a> for &'a String {
328	fn into_fragment(self) -> Fragment<'a> {
329		Fragment::Borrowed(BorrowedFragment::Internal {
330			text: self.as_str(),
331		})
332	}
333}
334
335impl IntoFragment<'_> for String {
336	fn into_fragment(self) -> Fragment<'static> {
337		Fragment::Owned(OwnedFragment::Internal {
338			text: self,
339		})
340	}
341}
342
343// Serialize Fragment<'a> by converting to OwnedFragment
344impl<'a> serde::Serialize for Fragment<'a> {
345	fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
346	where
347		S: serde::Serializer,
348	{
349		self.clone().into_owned().serialize(serializer)
350	}
351}
352
353// Deserialize always creates Fragment::Owned with OwnedFragment
354impl<'de, 'a> serde::Deserialize<'de> for Fragment<'a> {
355	fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
356	where
357		D: serde::Deserializer<'de>,
358	{
359		let owned = OwnedFragment::deserialize(deserializer)?;
360		Ok(Fragment::Owned(owned))
361	}
362}
363
364// PartialEq implementation for Fragment<'a>
365impl<'a> PartialEq for Fragment<'a> {
366	fn eq(&self, other: &Self) -> bool {
367		// Only compare text content, not source location
368		self.text() == other.text()
369	}
370}
371
372impl<'a> Eq for Fragment<'a> {}
373
374// Hash implementation for Fragment<'a> - only hashes the text content
375impl<'a> std::hash::Hash for Fragment<'a> {
376	fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
377		// Only hash the text content to be consistent with PartialEq
378		self.text().hash(state);
379	}
380}
381
382// AsRef<str> implementation for Fragment<'a>
383impl<'a> AsRef<str> for Fragment<'a> {
384	fn as_ref(&self) -> &str {
385		self.text()
386	}
387}