use std::{
borrow::Cow,
convert::Infallible,
fmt::{self, Display, Formatter},
};
use crate::{Indexer, Value, index_path::IndexPathState};
use thiserror::Error;
#[derive(Debug, Error, Eq, PartialEq, Clone)]
pub enum Error<'a> {
#[error("could not convert `{0:?}` to a map")]
CouldNotConvertToMap(Value<'a>),
#[error("could not append (`{0:?}`, `{1:?}`, `{2:?}`)")]
CouldNotAppend(Value<'a>, Option<Indexer<'a>>, Value<'a>),
#[error("parsing indexer ran into `{0:?}` in state `{1:?}` when parsing {2:?}")]
CouldNotParseIndexer(Option<char>, IndexPathState, Cow<'a, str>),
}
impl<'a> Error<'a> {
pub fn into_owned(self) -> Error<'static> {
match self {
Error::CouldNotConvertToMap(value) => Error::CouldNotConvertToMap(value.into_owned()),
Error::CouldNotAppend(value, indexer, value1) => Error::CouldNotAppend(
value.into_owned(),
indexer.map(Indexer::into_owned),
value1.into_owned(),
),
Error::CouldNotParseIndexer(a, b, c) => {
Error::CouldNotParseIndexer(a, b, Cow::Owned(c.into_owned()))
}
}
}
}
impl From<Infallible> for Error<'_> {
fn from(_: Infallible) -> Self {
unreachable!()
}
}
pub type Result<'a, T> = std::result::Result<T, Error<'a>>;
pub type ParseResult<'a, T> = std::result::Result<T, ParseErrors<'a>>;
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct ParseErrors<'a> {
input: Cow<'a, str>,
errors: Vec<Error<'a>>,
}
impl std::error::Error for ParseErrors<'_> {}
impl Display for ParseErrors<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
writeln!(
f,
"{} {} parsing {:?}:",
self.errors.len(),
if self.errors.len() == 1 {
"error"
} else {
"errors"
},
self.input
)?;
for error in &self.errors {
writeln!(f, " - {error}")?;
}
Ok(())
}
}
impl<'a> ParseErrors<'a> {
pub(crate) fn new(input: &'a str) -> Self {
Self {
input: input.into(),
errors: vec![],
}
}
pub(crate) fn push(&mut self, e: Error<'a>) {
self.errors.push(e)
}
pub fn into_owned(self) -> ParseErrors<'static> {
ParseErrors {
input: Cow::Owned(self.input.into_owned()),
errors: self.errors.into_iter().map(Error::into_owned).collect(),
}
}
pub fn input(&self) -> &str {
&self.input
}
pub fn errors(&self) -> &[Error<'a>] {
&self.errors
}
}