oxirs_core/rdfxml/
error.rs

1use crate::model::literal::LanguageTagParseError;
2use oxiri::IriParseError;
3// Note: EncodingError has been moved in newer versions of quick-xml
4use quick_xml::encoding::EncodingError;
5use quick_xml::escape::EscapeError;
6use quick_xml::events::attributes::AttrError;
7use std::io;
8use std::str::Utf8Error;
9use std::sync::Arc;
10
11/// Error returned during RDF/XML parsing.
12#[derive(Debug, thiserror::Error)]
13pub enum RdfXmlParseError {
14    /// I/O error during parsing (file not found...).
15    #[error(transparent)]
16    Io(#[from] io::Error),
17    /// An error in the file syntax.
18    #[error(transparent)]
19    Syntax(#[from] RdfXmlSyntaxError),
20    /// XML error during parsing.
21    #[error("XML error: {0}")]
22    XmlError(String),
23    /// Undefined prefix error.
24    #[error("Undefined prefix: {0}")]
25    UndefinedPrefix(String),
26    /// Invalid parse type error.
27    #[error("Invalid parse type: {0}")]
28    InvalidParseType(String),
29}
30
31impl From<RdfXmlParseError> for io::Error {
32    #[inline]
33    fn from(error: RdfXmlParseError) -> Self {
34        match error {
35            RdfXmlParseError::Io(error) => error,
36            RdfXmlParseError::Syntax(error) => error.into(),
37            RdfXmlParseError::XmlError(msg) => Self::new(io::ErrorKind::InvalidData, msg),
38            RdfXmlParseError::UndefinedPrefix(msg) => Self::new(
39                io::ErrorKind::InvalidData,
40                format!("Undefined prefix: {msg}"),
41            ),
42            RdfXmlParseError::InvalidParseType(msg) => Self::new(
43                io::ErrorKind::InvalidData,
44                format!("Invalid parse type: {msg}"),
45            ),
46        }
47    }
48}
49
50#[doc(hidden)]
51impl From<quick_xml::Error> for RdfXmlParseError {
52    #[inline]
53    fn from(error: quick_xml::Error) -> Self {
54        match error {
55            quick_xml::Error::Io(error) => {
56                Self::Io(Arc::try_unwrap(error).unwrap_or_else(|e| io::Error::new(e.kind(), e)))
57            }
58            _ => Self::Syntax(RdfXmlSyntaxError(SyntaxErrorKind::Xml(error))),
59        }
60    }
61}
62
63// EncodingError integration for quick-xml 0.37+
64#[doc(hidden)]
65impl From<EncodingError> for RdfXmlParseError {
66    fn from(error: EncodingError) -> Self {
67        Self::Syntax(RdfXmlSyntaxError::msg(error.to_string()))
68    }
69}
70
71#[doc(hidden)]
72impl From<AttrError> for RdfXmlParseError {
73    fn from(error: AttrError) -> Self {
74        quick_xml::Error::from(error).into()
75    }
76}
77
78impl From<crate::OxirsError> for RdfXmlParseError {
79    fn from(error: crate::OxirsError) -> Self {
80        Self::Syntax(RdfXmlSyntaxError::msg(error.to_string()))
81    }
82}
83
84impl From<IriParseError> for RdfXmlParseError {
85    fn from(error: IriParseError) -> Self {
86        Self::Syntax(RdfXmlSyntaxError(SyntaxErrorKind::InvalidIri {
87            iri: String::new(),
88            error,
89        }))
90    }
91}
92
93// Utf8Error conversion for quick-xml 0.38
94#[doc(hidden)]
95impl From<Utf8Error> for RdfXmlParseError {
96    fn from(error: Utf8Error) -> Self {
97        Self::Syntax(RdfXmlSyntaxError::msg(format!("UTF-8 error: {}", error)))
98    }
99}
100
101// EscapeError conversion for quick-xml 0.38
102#[doc(hidden)]
103impl From<EscapeError> for RdfXmlParseError {
104    fn from(error: EscapeError) -> Self {
105        Self::Syntax(RdfXmlSyntaxError::msg(format!("Escape error: {}", error)))
106    }
107}
108
109/// An error in the syntax of the parsed file.
110#[derive(Debug, thiserror::Error)]
111#[error(transparent)]
112pub struct RdfXmlSyntaxError(#[from] SyntaxErrorKind);
113
114#[derive(Debug, thiserror::Error)]
115enum SyntaxErrorKind {
116    #[error(transparent)]
117    Xml(#[from] quick_xml::Error),
118    #[error("error while parsing IRI '{iri}': {error}")]
119    InvalidIri {
120        iri: String,
121        #[source]
122        error: IriParseError,
123    },
124    #[error("error while parsing language tag '{tag}': {error}")]
125    InvalidLanguageTag {
126        tag: String,
127        #[source]
128        error: LanguageTagParseError,
129    },
130    #[error("{0}")]
131    Msg(String),
132}
133
134impl RdfXmlSyntaxError {
135    /// Builds an error from a printable error message.
136    pub(crate) fn msg(msg: impl Into<String>) -> Self {
137        Self(SyntaxErrorKind::Msg(msg.into()))
138    }
139
140    pub(crate) fn invalid_iri(iri: String, error: IriParseError) -> Self {
141        Self(SyntaxErrorKind::InvalidIri { iri, error })
142    }
143
144    pub(crate) fn invalid_language_tag(tag: String, error: LanguageTagParseError) -> Self {
145        Self(SyntaxErrorKind::InvalidLanguageTag { tag, error })
146    }
147}
148
149impl From<RdfXmlSyntaxError> for io::Error {
150    #[inline]
151    fn from(error: RdfXmlSyntaxError) -> Self {
152        match error.0 {
153            SyntaxErrorKind::Xml(error) => match error {
154                quick_xml::Error::Io(error) => {
155                    Arc::try_unwrap(error).unwrap_or_else(|e| Self::new(e.kind(), e))
156                }
157                _ => Self::new(io::ErrorKind::InvalidData, error),
158            },
159            SyntaxErrorKind::Msg(msg) => Self::new(io::ErrorKind::InvalidData, msg),
160            _ => Self::new(io::ErrorKind::InvalidData, error),
161        }
162    }
163}