reifydb_type/fragment/
owned.rs

1// Copyright (c) reifydb.com 2025
2// This file is licensed under the MIT, see license.md file
3
4use std::{
5	cmp::Ordering,
6	fmt::{Display, Formatter},
7};
8
9use serde::{Deserialize, Serialize};
10
11use super::{StatementColumn, StatementLine};
12
13/// Owned fragment - owns all its data
14#[derive(Debug, Clone, PartialEq, Hash, Serialize, Deserialize)]
15pub enum OwnedFragment {
16	/// No fragment information available
17	None,
18
19	/// Fragment from a RQL statement with position information
20	Statement {
21		text: String,
22		line: StatementLine,
23		column: StatementColumn,
24	},
25
26	/// Fragment from internal/runtime code
27	Internal {
28		text: String,
29	},
30}
31
32impl OwnedFragment {
33	/// Get the text value of the fragment
34	pub fn text(&self) -> &str {
35		match self {
36			OwnedFragment::None => "",
37			OwnedFragment::Statement {
38				text,
39				..
40			}
41			| OwnedFragment::Internal {
42				text,
43				..
44			} => text,
45		}
46	}
47
48	/// Get line position
49	pub fn line(&self) -> StatementLine {
50		match self {
51			OwnedFragment::Statement {
52				line,
53				..
54			} => *line,
55			_ => StatementLine(1),
56		}
57	}
58
59	/// Get column position
60	pub fn column(&self) -> StatementColumn {
61		match self {
62			OwnedFragment::Statement {
63				column,
64				..
65			} => *column,
66			_ => StatementColumn(0),
67		}
68	}
69
70	/// Convert to owned variant
71	pub fn into_owned(self) -> OwnedFragment {
72		self
73	}
74
75	/// Get a sub-fragment starting at the given offset with the given
76	/// length
77	pub fn sub_fragment(&self, offset: usize, length: usize) -> OwnedFragment {
78		let text = self.text();
79		let end = std::cmp::min(offset + length, text.len());
80		let sub_text = if offset < text.len() {
81			&text[offset..end]
82		} else {
83			""
84		};
85
86		match self {
87			OwnedFragment::None => OwnedFragment::None,
88			OwnedFragment::Statement {
89				line,
90				column,
91				..
92			} => OwnedFragment::Statement {
93				text: sub_text.to_string(),
94				line: *line,
95				column: StatementColumn(column.0 + offset as u32),
96			},
97			OwnedFragment::Internal {
98				..
99			} => OwnedFragment::Internal {
100				text: sub_text.to_string(),
101			},
102		}
103	}
104}
105
106impl OwnedFragment {
107	/// Create an internal fragment - useful for creating fragments from
108	/// substrings
109	pub fn internal(text: impl Into<String>) -> Self {
110		OwnedFragment::Internal {
111			text: text.into(),
112		}
113	}
114
115	/// Create a testing fragment - returns a Statement fragment for test
116	/// purposes
117	pub fn testing(text: impl Into<String>) -> Self {
118		OwnedFragment::Statement {
119			text: text.into(),
120			line: StatementLine(1),
121			column: StatementColumn(0),
122		}
123	}
124
125	/// Create an empty testing fragment
126	pub fn testing_empty() -> Self {
127		Self::testing("")
128	}
129
130	/// Merge multiple fragments (in any order) into one encompassing
131	/// fragment
132	pub fn merge_all(fragments: impl IntoIterator<Item = OwnedFragment>) -> OwnedFragment {
133		let mut fragments: Vec<OwnedFragment> = fragments.into_iter().collect();
134		assert!(!fragments.is_empty());
135
136		fragments.sort();
137
138		let first = fragments.first().unwrap();
139
140		let mut text = String::with_capacity(fragments.iter().map(|f| f.text().len()).sum());
141		for fragment in &fragments {
142			text.push_str(fragment.text());
143		}
144
145		match first {
146			OwnedFragment::None => OwnedFragment::None,
147			OwnedFragment::Statement {
148				line,
149				column,
150				..
151			} => OwnedFragment::Statement {
152				text,
153				line: *line,
154				column: *column,
155			},
156			OwnedFragment::Internal {
157				..
158			} => OwnedFragment::Internal {
159				text,
160			},
161		}
162	}
163
164	/// Compatibility: expose fragment field for Fragment compatibility
165	pub fn fragment(&self) -> &str {
166		self.text()
167	}
168}
169
170impl Default for OwnedFragment {
171	fn default() -> Self {
172		OwnedFragment::None
173	}
174}
175
176impl AsRef<str> for OwnedFragment {
177	fn as_ref(&self) -> &str {
178		self.text()
179	}
180}
181
182impl Display for OwnedFragment {
183	fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
184		Display::fmt(self.text(), f)
185	}
186}
187
188impl PartialOrd for OwnedFragment {
189	fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
190		Some(self.cmp(other))
191	}
192}
193
194impl Ord for OwnedFragment {
195	fn cmp(&self, other: &Self) -> Ordering {
196		self.column().cmp(&other.column()).then(self.line().cmp(&other.line()))
197	}
198}
199
200impl Eq for OwnedFragment {}