use std::num::{ParseFloatError, ParseIntError};
use raves_metadata_types::xmp::{
XmpElement, XmpValue,
parse_types::{XmpKind, XmpKindStructField},
};
pub type XmpValueResult = Result<XmpValue, XmpParsingError>;
pub type XmpElementResult = Result<XmpElement, XmpParsingError>;
use std::sync::Arc;
#[derive(Clone, Debug)]
#[repr(u8)]
pub enum XmpError {
NotUtf8,
XmlParseError(
Arc<xmltree::ParseError>,
),
NoRdfElement,
NoDescriptionElements,
}
impl core::cmp::PartialEq for XmpError {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::XmlParseError(a), Self::XmlParseError(b)) => {
core::ptr::eq(Arc::as_ptr(a), Arc::as_ptr(b))
}
_ => core::mem::discriminant(self) == core::mem::discriminant(other),
}
}
}
impl core::cmp::PartialOrd for XmpError {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
fn map_to_u8(e: &XmpError) -> u8 {
match e {
XmpError::NotUtf8 => 0_u8,
XmpError::XmlParseError(_) => 1_u8,
XmpError::NoRdfElement => 2_u8,
XmpError::NoDescriptionElements => 3_u8,
}
}
match (self, other) {
(Self::XmlParseError(a), Self::XmlParseError(b)) => {
Arc::as_ptr(a).partial_cmp(&Arc::as_ptr(b))
}
_ => map_to_u8(self).partial_cmp(&map_to_u8(other)),
}
}
}
impl core::hash::Hash for XmpError {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
if let XmpError::XmlParseError(a) = self {
Arc::as_ptr(a).hash(state);
}
core::mem::discriminant(self).hash(state);
}
}
impl core::fmt::Display for XmpError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
XmpError::NotUtf8 => f.write_str("The provided XMP data was invalid. It wasn't UTF-8."),
XmpError::XmlParseError(e) => {
write!(f, "Encountered error while parsing XML. err: {e}")
}
XmpError::NoRdfElement => {
f.write_str("The XML is missing the `rdf:Rdf` element, which is required.")
}
XmpError::NoDescriptionElements => f.write_str(
"The `rdf:Rdf` element has no `rdf:Description` elements. \
One or more are required.",
),
}
}
}
impl core::error::Error for XmpError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
XmpError::XmlParseError(e) => Some(e.as_ref()),
XmpError::NoRdfElement | XmpError::NoDescriptionElements | XmpError::NotUtf8 => None,
}
}
}
impl From<xmltree::ParseError> for XmpError {
fn from(value: xmltree::ParseError) -> Self {
XmpError::XmlParseError(value.into())
}
}
#[derive(Debug)]
pub enum XmpParsingError {
XmpElementCreationNoNamespace {
element_name: String,
},
XmpElementCreationNoPrefix {
element_name: String,
},
PrimitiveUnknownBool(
String,
),
PrimitiveIntegerParseFail(
String,
ParseIntError,
),
PrimitiveRealParseFail(
String,
ParseFloatError,
),
PrimitiveTextHadNoText {
element_name: String,
},
UnionDiscriminantWasntText {
element_name: String,
discriminant_kind: &'static XmpKindStructField,
},
UnionNoDiscriminant {
element_name: String,
},
ArrayNoInnerCollectionType {
element_name: String,
children: Vec<xmltree::XMLNode>,
},
ArrayAltNoDefault {
element_name: String,
alternatives_array: Vec<(String, XmpElement)>,
},
ArrayGivenNonArraySchema {
element_name: String,
weird_schema: &'static XmpKind,
},
GenericLikelyPrimitiveHadNoText {
element_name: String,
},
GenericNoOtherOption {
element_name: String,
},
}
impl core::fmt::Display for XmpParsingError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
XmpParsingError::XmpElementCreationNoNamespace { element_name } => write!(
f,
"The XML element `{element_name}` has no namespace. \
Couldn't create an `XmpElement`.",
),
XmpParsingError::XmpElementCreationNoPrefix { element_name } => write!(
f,
"The XML element `{element_name}` has a namespace, but no prefix. \
Couldn't create an `XmpElement`.",
),
XmpParsingError::PrimitiveUnknownBool(got) => write!(
f,
"Asked to parse out a Boolean, but the stored value wasn't \
an expected answer. \
Instead, it was: `{got}`",
),
XmpParsingError::PrimitiveIntegerParseFail(got, parse_int_err) => write!(
f,
"Asked to parse out an Integer, but the stored value wasn't right. \
- got: `{got}`, \
- err: {parse_int_err}",
),
XmpParsingError::PrimitiveRealParseFail(got, parse_float_err) => write!(
f,
"Asked to parse out a Real, but the stored value wasn't right. \
- got: `{got}`, \
- err: {parse_float_err}",
),
XmpParsingError::PrimitiveTextHadNoText { element_name } => write!(
f,
"Element `{element_name}` was a `Primitive::Text` kind, but didn't provide text.",
),
XmpParsingError::UnionDiscriminantWasntText {
element_name,
discriminant_kind,
} => write!(
f,
"Union `{element_name}` had a discriminant, but it wasn't `Kind::Simple(Prim::Text)`! \
found kind: {discriminant_kind:#?}",
),
XmpParsingError::UnionNoDiscriminant { element_name } => write!(
f,
"Element `{element_name}` was a `Primitive::Text` kind, but didn't provide text.",
),
XmpParsingError::ArrayNoInnerCollectionType {
element_name,
children,
} => write!(
f,
"Array `{element_name}` had no inner collection type! \
- known child elements: {children:#?}",
),
XmpParsingError::ArrayAltNoDefault {
element_name,
alternatives_array,
} => write!(
f,
"Alternatives array `{element_name}` had alternatives, but didn't \
specify a default! \
- found alternatives: {alternatives_array:#?}",
),
XmpParsingError::ArrayGivenNonArraySchema {
element_name,
weird_schema,
} => write!(
f,
"List-like array `{element_name}` had a weird schema - it \
wasn't for an array. \n\
- schema: {weird_schema:?}",
),
XmpParsingError::GenericLikelyPrimitiveHadNoText { element_name } => write!(
f,
"Generic element `{element_name}` was a primitive, but didn't provide text.",
),
XmpParsingError::GenericNoOtherOption { element_name } => {
write!(f, "Generic element `{element_name}` was blank.",)
}
}
}
}
impl core::error::Error for XmpParsingError {}