use std::{
collections::VecDeque,
fmt::Display,
num::ParseIntError,
str::Utf8Error,
sync::{MutexGuard, PoisonError},
};
use base64::DecodeError;
use serde::{ser::SerializeStruct, Serialize, Serializer};
use crate::{
mzml::{attributes::AttributeType, Tag},
obo::ValueType,
};
#[derive(Debug)]
pub enum ParseError {
IntError((Tag, ParseIntError)),
Utf8Error((Tag, Utf8Error)),
XMLError((Tag, quick_xml::Error)),
UnexpectedAttribute((Tag, String)),
MissingAttribute((Tag, String)),
MissingAttributeValue((Tag, String, AttributeType)),
UnexpectedTag(String),
MissingRef {
breadcrumbs: Breadcrumbs,
tag: Tag,
ref_to_tag: Tag,
ref_id: String,
},
MissingValue((Breadcrumbs, String, ValueType)),
UnexpectedValue((Breadcrumbs, String, String)),
InvalidValue((Breadcrumbs, String, String)),
UnknownAccession((Breadcrumbs, String)),
}
impl ParseError {
pub fn description(&self) -> String {
match self {
ParseError::IntError((tag, int_error)) => {
format!("Couldn't convert integer at tag {}: {}", tag, int_error)
}
ParseError::Utf8Error(_) => todo!(),
ParseError::XMLError(_) => todo!(),
ParseError::UnexpectedAttribute((tag, string)) => {
format!("{} tag has an unexpected attribute {}", tag, string)
}
ParseError::MissingAttribute((tag, string)) => {
format!("{} tag is missing required attribute. {}", tag, string)
}
ParseError::MissingAttributeValue((tag, attribute, attribute_type)) => {
format!(
"{} tag is missing value of type {:?} for attribute {}",
tag, attribute_type, attribute
)
}
ParseError::UnexpectedTag(string) => {
format!("Unexpected tag: {}", string)
}
ParseError::MissingRef {
breadcrumbs: _breadcrumbs,
tag,
ref_to_tag,
ref_id,
} => {
format!(
"Tag {} includes a reference to a {} tag with id {}, but this doesn't exist",
tag, ref_to_tag, ref_id
)
}
ParseError::MissingValue((_breadcrumbs, data, value_type)) => {
format!(
" Missing value of type {:?} for cvParam {}",
value_type, data
)
}
ParseError::InvalidValue((_breadcrumbs, data, value)) => {
format!("Found an invalid value ({}) for cvParam {}", value, data)
}
ParseError::UnexpectedValue((_breadcrumbs, data, value)) => {
format!(
"Found a value ({}) when one wasn't expected for cvParam {}",
value, data
)
}
ParseError::UnknownAccession((_breadcrumbs, accession)) => {
format!(
"Found an accession (cvParam) ({}) that was not present in the ontology",
accession
)
}
}
}
}
impl Display for ParseError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ParseError::IntError(_) => {
write!(f, "{}", self.description())
}
ParseError::Utf8Error(_) => {
write!(f, "{}", self.description())
},
ParseError::XMLError(_) => {
write!(f, "{}", self.description())
},
ParseError::UnexpectedAttribute(_) => {
write!(f, "{}", self.description())
}
ParseError::MissingAttribute(_) => {
write!(f, "{}", self.description())
}
ParseError::MissingAttributeValue(_) => {
write!(f, "{}", self.description())
}
ParseError::UnexpectedTag(_) => {
write!(f, "{}", self.description())
}
ParseError::MissingRef {
breadcrumbs,
tag: _,
ref_to_tag: _,
ref_id: _,
} => {
write!(
f,
"[{}] {}",
breadcrumbs, self.description()
)
}
ParseError::MissingValue((breadcrumbs, _data, _value_type)) => {
write!(
f,
"[{}] {}",
breadcrumbs, self.description()
)
}
ParseError::InvalidValue((breadcrumbs, _data, _value)) => {
write!(
f,
"[{}] {}",
breadcrumbs, self.description()
)
}
ParseError::UnexpectedValue((breadcrumbs, _data, _value)) => {
write!(
f,
"[{}] {}",
breadcrumbs, self.description()
)
}
ParseError::UnknownAccession((breadcrumbs, _accession)) => {
write!(
f,
"[{}] {}",
breadcrumbs, self.description()
)
}
}
}
}
impl Serialize for ParseError {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut state = serializer.serialize_struct("parse_error", 2)?;
match self {
ParseError::IntError((tag, _error)) => {
state.serialize_field("type", "IntError")?;
state.serialize_field("tag", tag)?;
state.serialize_field("description", &self.description())?;
}
ParseError::Utf8Error((tag, _error)) => {
state.serialize_field("type", "Utf8Error")?;
state.serialize_field("tag", tag)?;
state.serialize_field("description", &self.description())?;
}
ParseError::XMLError((tag, _error)) => {
state.serialize_field("type", "XMLError")?;
state.serialize_field("tag", tag)?;
state.serialize_field("description", &self.description())?;
}
ParseError::UnexpectedAttribute((tag, _error)) => {
state.serialize_field("type", "UnexpectedAttribute")?;
state.serialize_field("tag", tag)?;
state.serialize_field("description", &self.description())?;
}
ParseError::MissingAttribute((tag, _error)) => {
state.serialize_field("type", "MissingAttribute")?;
state.serialize_field("tag", tag)?;
state.serialize_field("description", &self.description())?;
}
ParseError::MissingAttributeValue((tag, _attribute, _attribute_value)) => {
state.serialize_field("type", "MissingAttributeValue")?;
state.serialize_field("tag", tag)?;
state.serialize_field("description", &self.description())?;
}
ParseError::UnexpectedTag(_) => {
state.serialize_field("type", "UnexpectedTag")?;
state.serialize_field("description", &self.description())?;
}
ParseError::MissingRef {
breadcrumbs,
tag,
ref_to_tag,
ref_id,
} => {
state.serialize_field("type", "MissingRef")?;
state.serialize_field("tag", tag)?;
state.serialize_field("description", &self.description())?;
state.serialize_field("location", &format!("{}", breadcrumbs))?;
state.serialize_field("ref_to_tag", ref_to_tag)?;
state.serialize_field("ref_id", ref_id)?;
}
ParseError::MissingValue((breadcrumbs, _details, value_type)) => {
state.serialize_field("type", "MissingValue")?;
state.serialize_field("description", &self.description())?;
state.serialize_field("location", &format!("{}", breadcrumbs))?;
state.serialize_field("expected_value_type", value_type)?;
}
ParseError::UnexpectedValue((breadcrumbs, _, _)) => {
state.serialize_field("type", "UnexpectedValue")?;
state.serialize_field("description", &self.description())?;
state.serialize_field("location", &format!("{}", breadcrumbs))?;
}
ParseError::InvalidValue((breadcrumbs, _, _)) => {
state.serialize_field("type", "InvalidValue")?;
state.serialize_field("description", &self.description())?;
state.serialize_field("location", &format!("{}", breadcrumbs))?;
}
ParseError::UnknownAccession((breadcrumbs, _)) => {
state.serialize_field("type", "UnknownAccession")?;
state.serialize_field("description", &self.description())?;
state.serialize_field("location", &format!("{}", breadcrumbs))?;
}
}
state.end()
}
}
#[derive(Debug, Clone)]
pub struct Breadcrumbs(pub VecDeque<(Tag, Option<String>)>);
impl std::fmt::Display for Breadcrumbs {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
for (index, (tag, id)) in self.0.iter().enumerate() {
if index > 0 {
write!(f, ">")?;
}
write!(f, "{}", tag)?;
if let Some(id) = id {
write!(f, "[{}]", id)?;
}
}
Ok(())
}
}
#[non_exhaustive]
#[derive(Debug)]
pub enum FatalParseError {
IOError(std::io::Error),
XMLError(quick_xml::Error),
UnexpectedTag(String),
InvalidTag((Tag, String)),
MissingOpeningTag(String),
MissingClosingTag(String),
UnexpectedError(String),
InvalidUtf8(Utf8Error),
UnexpectedEvent(String),
}
impl Serialize for FatalParseError {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut state = serializer.serialize_struct("fatal_error", 2)?;
match self {
FatalParseError::IOError(error) => {
state.serialize_field("type", "IOError")?;
state.serialize_field("details", &format!("{}", error))?;
}
FatalParseError::XMLError(error) => {
state.serialize_field("type", "XMLError")?;
state.serialize_field("details", &format!("{}", error))?;
}
FatalParseError::UnexpectedTag(error) => {
state.serialize_field("type", "UnexpectedTag")?;
state.serialize_field("details", error)?;
}
FatalParseError::MissingOpeningTag(error) => {
state.serialize_field("type", "MissingOpeningTag")?;
state.serialize_field("details", error)?;
}
FatalParseError::MissingClosingTag(error) => {
state.serialize_field("type", "MissingOpeningTag")?;
state.serialize_field("details", error)?;
}
FatalParseError::UnexpectedError(error) => {
state.serialize_field("type", "UnexpectedError")?;
state.serialize_field("details", error)?;
}
FatalParseError::UnexpectedEvent(error) => {
state.serialize_field("type", "UnexpectedEvent")?;
state.serialize_field("details", error)?;
}
FatalParseError::InvalidUtf8(error) => {
state.serialize_field("type", "InvalidUtf8")?;
state.serialize_field("details", &format!("{:?}", error))?;
}
FatalParseError::InvalidTag((tag, error)) => {
state.serialize_field("type", "InvalidTag")?;
state.serialize_field("tag", &format!("{}", tag))?;
state.serialize_field("details", error)?;
}
}
state.end()
}
}
impl From<std::io::Error> for FatalParseError {
fn from(error: std::io::Error) -> Self {
FatalParseError::IOError(error)
}
}
impl From<Utf8Error> for FatalParseError {
fn from(error: Utf8Error) -> Self {
FatalParseError::InvalidUtf8(error)
}
}
impl From<quick_xml::Error> for FatalParseError {
fn from(error: quick_xml::Error) -> Self {
FatalParseError::XMLError(error)
}
}
#[derive(Debug)]
pub enum DataError {
MutexError,
IOError(std::io::Error),
Base64DecodeError(DecodeError),
UnknownDataType,
}
impl<'a, D> From<PoisonError<MutexGuard<'a, D>>> for DataError {
fn from(_poison_error: PoisonError<MutexGuard<'a, D>>) -> Self {
Self::MutexError
}
}
impl From<std::io::Error> for DataError {
fn from(io_error: std::io::Error) -> Self {
Self::IOError(io_error)
}
}
impl From<DecodeError> for DataError {
fn from(decode_error: DecodeError) -> Self {
Self::Base64DecodeError(decode_error)
}
}