use crate::Parser;
use core::{
fmt::{self, Display},
marker::PhantomData,
};
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct ParseError<'a> {
start_offset: u32,
end_offset: u32,
direction: ParseDirection,
kind: ErrorKind,
extra_message: &'static &'static str,
_lifetime: PhantomData<&'a [u8]>,
}
impl<'a> ParseError<'a> {
#[inline(always)]
pub const fn new(parser: Parser<'a>, kind: ErrorKind) -> Self {
Self {
start_offset: parser.start_offset,
end_offset: parser.start_offset + parser.str.len() as u32,
direction: parser.parse_direction,
kind,
extra_message: &"",
_lifetime: PhantomData,
}
}
pub const fn other_error(parser: Parser<'a>, extra_message: &'static &'static str) -> Self {
Self {
start_offset: parser.start_offset,
end_offset: parser.start_offset + parser.str.len() as u32,
direction: parser.parse_direction,
kind: ErrorKind::Other,
extra_message,
_lifetime: PhantomData,
}
}
pub const fn copy(&self) -> Self {
Self {
start_offset: self.start_offset,
end_offset: self.end_offset,
direction: self.direction,
kind: self.kind,
extra_message: self.extra_message,
_lifetime: PhantomData,
}
}
#[inline(always)]
pub const fn offset(&self) -> usize {
(match self.direction {
ParseDirection::FromStart | ParseDirection::FromBoth => self.start_offset,
ParseDirection::FromEnd => self.end_offset,
}) as usize
}
pub const fn error_direction(&self) -> ParseDirection {
self.direction
}
pub const fn kind(&self) -> ErrorKind {
self.kind
}
const fn extra_message(&self) -> &str {
self.extra_message
}
#[track_caller]
pub const fn panic(&self) -> ! {
use const_panic::{FmtArg, PanicVal};
const_panic::concat_panic(&[&[
PanicVal::write_str(self.error_for_direction()),
PanicVal::from_usize(self.offset(), FmtArg::DEBUG),
PanicVal::write_str(" byte offset"),
PanicVal::write_str(self.error_suffix()),
PanicVal::write_str(self.extra_message()),
]])
}
const fn error_for_direction(&self) -> &'static str {
match self.direction {
ParseDirection::FromStart => "error from the start at the ",
ParseDirection::FromEnd => "error from the end at the ",
ParseDirection::FromBoth => "error from the start and end at the ",
}
}
const fn error_suffix(&self) -> &'static str {
match self.kind {
ErrorKind::ParseInteger => " while parsing an integer",
ErrorKind::ParseBool => " while parsing a bool",
ErrorKind::Find => " while trying to find and skip a pattern",
ErrorKind::Strip => " while trying to strip a pattern",
ErrorKind::SplitExhausted => ": called split on empty parser",
ErrorKind::DelimiterNotFound => ": delimiter (for splitting) could not be found",
ErrorKind::Other => {
if self.extra_message.is_empty() {
" other error"
} else {
": "
}
}
}
}
}
impl<'a> Display for ParseError<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.error_for_direction())?;
Display::fmt(&self.offset(), f)?;
f.write_str(" byte offset")?;
f.write_str(self.error_suffix())?;
f.write_str(self.extra_message())?;
Ok(())
}
}
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum ParseDirection {
FromStart = 0,
FromEnd = 1,
FromBoth = 2,
}
#[non_exhaustive]
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum ErrorKind {
ParseInteger,
ParseBool,
Find,
Strip,
SplitExhausted,
DelimiterNotFound,
Other,
}
pub type ParserResult<'a, E = ParseError<'a>> = Result<Parser<'a>, E>;
pub type ParseValueResult<'a, T, E = ParseError<'a>> = Result<(T, Parser<'a>), E>;