use std::fmt;
use thiserror::Error;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct XmlPath(String);
impl XmlPath {
pub(crate) fn new(path: String) -> Self {
Self(path)
}
#[must_use]
pub fn as_str(&self) -> &str {
&self.0
}
}
impl fmt::Display for XmlPath {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str(&self.0)
}
}
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum XmlError {
#[error("malformed XML: {0}")]
Malformed(String),
#[error("unparseable entity id {0:?}")]
BadId(String),
#[error("invalid {kind} scalar {value:?}")]
InvalidScalar {
kind: String,
value: String,
},
#[error("unknown value kind {0:?}")]
UnknownKind(String),
#[error("`{name}` names slot {slot}, which is already set")]
DuplicateSlot {
name: String,
slot: usize,
},
#[error("`{name}` names slot {slot}, but slot {missing} is absent")]
MissingSlot {
name: String,
slot: usize,
missing: usize,
},
#[error("element `{element}` has namespace {found:?}; expected `{expected}`")]
Namespace {
element: String,
expected: &'static str,
found: Option<String>,
},
#[error("ifcXML profile expects schema `{expected}`, found {found:?}")]
Profile {
expected: &'static str,
found: Option<String>,
},
#[error("strict ifcXML requires root `ifcXML`, found {found:?}")]
Root {
found: Option<String>,
},
#[error("{path}: {source}")]
At {
path: XmlPath,
#[source]
source: Box<XmlError>,
},
#[error("write failed: {0}")]
Write(String),
}
impl XmlError {
#[must_use]
pub fn path(&self) -> Option<&XmlPath> {
match self {
Self::At { path, .. } => Some(path),
_ => None,
}
}
#[must_use]
pub fn root_cause(&self) -> &Self {
match self {
Self::At { source, .. } => source.root_cause(),
error => error,
}
}
pub(crate) fn at(self, path: String) -> Self {
match self {
Self::At { .. } => self,
source => Self::At {
path: XmlPath::new(path),
source: Box::new(source),
},
}
}
}
impl From<quick_xml::Error> for XmlError {
fn from(error: quick_xml::Error) -> Self {
Self::Malformed(error.to_string())
}
}