1use serde::{Deserialize, Serialize};
6use std::error::Error;
7use std::fmt;
8use std::io;
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
12pub struct TextPosition {
13 pub line: usize,
15 pub column: usize,
17 pub offset: usize,
19}
20
21impl TextPosition {
22 pub fn new(line: usize, column: usize, offset: usize) -> Self {
24 Self {
25 line,
26 column,
27 offset,
28 }
29 }
30
31 pub fn start() -> Self {
33 Self::new(1, 1, 0)
34 }
35}
36
37impl fmt::Display for TextPosition {
38 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39 write!(f, "line {}, column {}", self.line, self.column)
40 }
41}
42
43#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
45pub struct RdfSyntaxError {
46 pub message: String,
48 pub position: Option<TextPosition>,
50 pub context: Option<String>,
52}
53
54impl RdfSyntaxError {
55 pub fn new(message: impl Into<String>) -> Self {
57 Self {
58 message: message.into(),
59 position: None,
60 context: None,
61 }
62 }
63
64 pub fn with_position(message: impl Into<String>, position: TextPosition) -> Self {
66 Self {
67 message: message.into(),
68 position: Some(position),
69 context: None,
70 }
71 }
72
73 pub fn with_context(
75 message: impl Into<String>,
76 position: TextPosition,
77 context: impl Into<String>,
78 ) -> Self {
79 Self {
80 message: message.into(),
81 position: Some(position),
82 context: Some(context.into()),
83 }
84 }
85
86 pub fn at_position(mut self, position: TextPosition) -> Self {
88 self.position = Some(position);
89 self
90 }
91
92 pub fn with_context_str(mut self, context: impl Into<String>) -> Self {
94 self.context = Some(context.into());
95 self
96 }
97}
98
99impl fmt::Display for RdfSyntaxError {
100 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
101 write!(f, "Syntax error: {}", self.message)?;
102
103 if let Some(position) = &self.position {
104 write!(f, " at {position}")?;
105 }
106
107 if let Some(context) = &self.context {
108 write!(f, "\nContext: {context}")?;
109 }
110
111 Ok(())
112 }
113}
114
115impl Error for RdfSyntaxError {}
116
117#[derive(Debug)]
119pub enum RdfParseError {
120 Syntax(RdfSyntaxError),
122 Io(io::Error),
124 InvalidIri(String),
126 InvalidLiteral(String),
128 InvalidBlankNode(String),
130 InvalidDatatype(String),
132 InvalidLanguageTag(String),
134 UnsupportedFeature(String),
136 Internal(String),
138}
139
140impl RdfParseError {
141 pub fn syntax(message: impl Into<String>) -> Self {
143 Self::Syntax(RdfSyntaxError::new(message))
144 }
145
146 pub fn syntax_at(message: impl Into<String>, position: TextPosition) -> Self {
148 Self::Syntax(RdfSyntaxError::with_position(message, position))
149 }
150
151 pub fn invalid_iri(iri: impl Into<String>) -> Self {
153 Self::InvalidIri(iri.into())
154 }
155
156 pub fn invalid_literal(literal: impl Into<String>) -> Self {
158 Self::InvalidLiteral(literal.into())
159 }
160
161 pub fn unsupported(feature: impl Into<String>) -> Self {
163 Self::UnsupportedFeature(feature.into())
164 }
165
166 pub fn internal(message: impl Into<String>) -> Self {
168 Self::Internal(message.into())
169 }
170}
171
172impl fmt::Display for RdfParseError {
173 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
174 match self {
175 Self::Syntax(err) => write!(f, "{err}"),
176 Self::Io(err) => write!(f, "I/O error: {err}"),
177 Self::InvalidIri(iri) => write!(f, "Invalid IRI: {iri}"),
178 Self::InvalidLiteral(literal) => write!(f, "Invalid literal: {literal}"),
179 Self::InvalidBlankNode(bnode) => write!(f, "Invalid blank node: {bnode}"),
180 Self::InvalidDatatype(datatype) => write!(f, "Invalid datatype: {datatype}"),
181 Self::InvalidLanguageTag(tag) => write!(f, "Invalid language tag: {tag}"),
182 Self::UnsupportedFeature(feature) => write!(f, "Unsupported feature: {feature}"),
183 Self::Internal(msg) => write!(f, "Internal error: {msg}"),
184 }
185 }
186}
187
188impl Error for RdfParseError {
189 fn source(&self) -> Option<&(dyn Error + 'static)> {
190 match self {
191 Self::Syntax(err) => Some(err),
192 Self::Io(err) => Some(err),
193 _ => None,
194 }
195 }
196}
197
198impl From<io::Error> for RdfParseError {
199 fn from(err: io::Error) -> Self {
200 Self::Io(err)
201 }
202}
203
204impl From<RdfSyntaxError> for RdfParseError {
205 fn from(err: RdfSyntaxError) -> Self {
206 Self::Syntax(err)
207 }
208}
209
210impl From<crate::OxirsError> for RdfParseError {
211 fn from(err: crate::OxirsError) -> Self {
212 match err {
213 crate::OxirsError::Parse(msg) => Self::syntax(msg),
214 crate::OxirsError::Io(msg) => Self::syntax(format!("IO error: {msg}")),
215 crate::OxirsError::Store(msg) => Self::internal(format!("Store error: {msg}")),
216 crate::OxirsError::Query(msg) => Self::internal(format!("Query error: {msg}")),
217 crate::OxirsError::Serialize(msg) => {
218 Self::internal(format!("Serialization error: {msg}"))
219 }
220 crate::OxirsError::QuantumError(msg) => Self::internal(format!("Quantum error: {msg}")),
221 crate::OxirsError::MolecularError(msg) => {
222 Self::internal(format!("Molecular error: {msg}"))
223 }
224 crate::OxirsError::NeuralSymbolicError(msg) => {
225 Self::internal(format!("Neural-symbolic error: {msg}"))
226 }
227 crate::OxirsError::ConcurrencyError(msg) => {
228 Self::internal(format!("Concurrency error: {msg}"))
229 }
230 crate::OxirsError::NotSupported(msg) => {
231 Self::unsupported(format!("Not supported: {msg}"))
232 }
233 crate::OxirsError::Update(msg) => Self::internal(format!("Update error: {msg}")),
234 crate::OxirsError::Federation(msg) => {
235 Self::internal(format!("Federation error: {msg}"))
236 }
237 }
238 }
239}
240
241impl From<crate::model::literal::LanguageTagParseError> for RdfParseError {
243 fn from(err: crate::model::literal::LanguageTagParseError) -> Self {
244 Self::InvalidLanguageTag(err.to_string())
245 }
246}
247
248#[derive(Debug)]
250pub enum FormatError {
251 Parse(RdfParseError),
253 Serialize(io::Error),
255 UnsupportedFormat(String),
257 InvalidData(String),
259 MissingComponent(String),
261 Configuration(String),
263}
264
265impl FormatError {
266 pub fn unsupported_format(format: impl Into<String>) -> Self {
268 Self::UnsupportedFormat(format.into())
269 }
270
271 pub fn invalid_data(message: impl Into<String>) -> Self {
273 Self::InvalidData(message.into())
274 }
275
276 pub fn missing_component(component: impl Into<String>) -> Self {
278 Self::MissingComponent(component.into())
279 }
280
281 pub fn configuration(message: impl Into<String>) -> Self {
283 Self::Configuration(message.into())
284 }
285}
286
287impl fmt::Display for FormatError {
288 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
289 match self {
290 Self::Parse(err) => write!(f, "Parse error: {err}"),
291 Self::Serialize(err) => write!(f, "Serialization error: {err}"),
292 Self::UnsupportedFormat(format) => write!(f, "Unsupported format: {format}"),
293 Self::InvalidData(msg) => write!(f, "Invalid data: {msg}"),
294 Self::MissingComponent(component) => write!(f, "Missing component: {component}"),
295 Self::Configuration(msg) => write!(f, "Configuration error: {msg}"),
296 }
297 }
298}
299
300impl Error for FormatError {
301 fn source(&self) -> Option<&(dyn Error + 'static)> {
302 match self {
303 Self::Parse(err) => Some(err),
304 Self::Serialize(err) => Some(err),
305 _ => None,
306 }
307 }
308}
309
310impl From<RdfParseError> for FormatError {
311 fn from(err: RdfParseError) -> Self {
312 Self::Parse(err)
313 }
314}
315
316impl From<io::Error> for FormatError {
317 fn from(err: io::Error) -> Self {
318 Self::Serialize(err)
319 }
320}
321
322impl From<RdfSyntaxError> for FormatError {
323 fn from(err: RdfSyntaxError) -> Self {
324 Self::Parse(err.into())
325 }
326}
327
328pub type ParseResult<T> = Result<T, RdfParseError>;
330
331pub type SerializeResult<T> = Result<T, io::Error>;
333
334pub type FormatResult<T> = Result<T, FormatError>;
336
337#[cfg(test)]
338mod tests {
339 use super::*;
340
341 #[test]
342 fn test_text_position() {
343 let pos = TextPosition::new(10, 5, 100);
344 assert_eq!(pos.line, 10);
345 assert_eq!(pos.column, 5);
346 assert_eq!(pos.offset, 100);
347
348 let start = TextPosition::start();
349 assert_eq!(start.line, 1);
350 assert_eq!(start.column, 1);
351 assert_eq!(start.offset, 0);
352 }
353
354 #[test]
355 fn test_syntax_error() {
356 let err = RdfSyntaxError::new("Invalid syntax");
357 assert_eq!(err.message, "Invalid syntax");
358 assert!(err.position.is_none());
359
360 let pos = TextPosition::new(5, 10, 50);
361 let err_with_pos = RdfSyntaxError::with_position("Bad token", pos);
362 assert_eq!(err_with_pos.position, Some(pos));
363 }
364
365 #[test]
366 fn test_parse_error() {
367 let syntax_err = RdfParseError::syntax("Bad syntax");
368 assert!(matches!(syntax_err, RdfParseError::Syntax(_)));
369
370 let iri_err = RdfParseError::invalid_iri("not-an-iri");
371 assert!(matches!(iri_err, RdfParseError::InvalidIri(_)));
372
373 let unsupported_err = RdfParseError::unsupported("Some feature");
374 assert!(matches!(
375 unsupported_err,
376 RdfParseError::UnsupportedFeature(_)
377 ));
378 }
379
380 #[test]
381 fn test_format_error() {
382 let format_err = FormatError::unsupported_format("unknown/format");
383 assert!(matches!(format_err, FormatError::UnsupportedFormat(_)));
384
385 let data_err = FormatError::invalid_data("Bad data");
386 assert!(matches!(data_err, FormatError::InvalidData(_)));
387 }
388
389 #[test]
390 fn test_error_conversion() {
391 let syntax_err = RdfSyntaxError::new("Bad syntax");
392 let parse_err: RdfParseError = syntax_err.into();
393 let format_err: FormatError = parse_err.into();
394
395 assert!(matches!(format_err, FormatError::Parse(_)));
396 }
397}