use std::fmt;
#[derive(Debug, PartialEq, Eq, Clone, Hash)]
pub(crate) enum ErrorData {
Eof,
LimitExceeded,
Text(String),
}
impl ErrorData {
pub fn len(&self) -> usize {
match self {
Self::Eof | Self::LimitExceeded => 0,
Self::Text(text) => text.len(),
}
}
}
impl fmt::Display for ErrorData {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Eof => write!(f, "EOF"),
Self::LimitExceeded => Ok(()),
Self::Text(text) => write!(f, "{text}"),
}
}
}
#[derive(PartialEq, Eq, Clone, Hash, thiserror::Error)]
#[error("ERROR@{index}:{} {message:?} {data}", .index + .data.len())]
pub struct Error {
pub(crate) message: String,
pub(crate) data: ErrorData,
pub(crate) index: usize,
}
impl Error {
pub fn with_loc<S: Into<String>>(message: S, data: String, index: usize) -> Self {
Self {
message: message.into(),
data: ErrorData::Text(data),
index,
}
}
pub fn limit<S: Into<String>>(message: S, index: usize) -> Self {
Self {
message: message.into(),
data: ErrorData::LimitExceeded,
index,
}
}
pub fn eof<S: Into<String>>(message: S, index: usize) -> Self {
Self {
message: message.into(),
data: ErrorData::Eof,
index,
}
}
pub fn data(&self) -> &str {
match &self.data {
ErrorData::Text(text) => text,
_ => "",
}
}
pub fn is_limit(&self) -> bool {
matches!(&self.data, ErrorData::LimitExceeded)
}
pub fn is_eof(&self) -> bool {
matches!(&self.data, ErrorData::Eof)
}
pub(crate) fn set_data(&mut self, data: String) {
self.data = ErrorData::Text(data);
}
pub fn index(&self) -> usize {
self.index
}
pub fn message(&self) -> &str {
self.message.as_ref()
}
}
impl fmt::Debug for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let start = self.index;
let end = self.index + self.data.len();
write!(
f,
"ERROR@{}:{} {:?} {}",
start, end, self.message, self.data
)
}
}