use core::ops::AddAssign;
use crate::{
error::InvalidHexDigits,
utils::{SimpleSpan, human_display::DisplayHuman},
};
use derive_more::{From, IsVariant, TryUnwrap, Unwrap};
pub type InvalidHexEscapeDigits<Char, Offset> = InvalidHexDigits<Char, 2, Offset>;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct IncompleteHexEscape<O = usize>(SimpleSpan<O>);
impl<O> core::fmt::Display for IncompleteHexEscape<O>
where
O: core::fmt::Display,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(
f,
"incomplete hexadecimal escape sequence at {}, hexadecimal escape must contains exactly two hexadecimal digits",
self.0
)
}
}
impl<O> core::error::Error for IncompleteHexEscape<O> where O: core::fmt::Debug + core::fmt::Display {}
impl<O> IncompleteHexEscape<O> {
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn new(span: SimpleSpan<O>) -> Self {
Self(span)
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn span(&self) -> SimpleSpan<O>
where
O: Copy,
{
self.0
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn span_ref(&self) -> SimpleSpan<&O> {
self.0.as_ref()
}
#[inline]
pub fn bump(&mut self, n: &O) -> &mut Self
where
O: for<'a> AddAssign<&'a O> + Clone,
{
self.0.bump(n);
self
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct MalformedHexEscape<Char = char, O = usize> {
digits: InvalidHexEscapeDigits<Char, O>,
span: SimpleSpan<O>,
}
impl<Char, O> core::fmt::Display for MalformedHexEscape<Char, O>
where
Char: DisplayHuman,
O: core::fmt::Display,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(
f,
"malformed hexadecimal escape sequence with invalid digits at {}, {}",
self.span,
self.digits_ref()
)
}
}
impl<Char, O> core::error::Error for MalformedHexEscape<Char, O>
where
Char: DisplayHuman + core::fmt::Debug,
O: core::fmt::Debug + core::fmt::Display,
{
}
impl<Char, O> MalformedHexEscape<Char, O> {
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn new(digits: InvalidHexEscapeDigits<Char, O>, span: SimpleSpan<O>) -> Self {
Self { digits, span }
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn digits(&self) -> InvalidHexEscapeDigits<Char, O>
where
Char: Clone,
O: Clone,
{
self.digits.clone()
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn digits_ref(&self) -> &InvalidHexEscapeDigits<Char, O> {
&self.digits
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn digits_mut(&mut self) -> &mut InvalidHexEscapeDigits<Char, O> {
&mut self.digits
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn span(&self) -> SimpleSpan<O>
where
O: Copy,
{
self.span
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn span_ref(&self) -> SimpleSpan<&O> {
self.span.as_ref()
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn span_mut(&mut self) -> SimpleSpan<&mut O> {
self.span.as_mut()
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn bump(&mut self, n: &O) -> &mut Self
where
O: for<'a> AddAssign<&'a O> + Clone,
{
self.span.bump(n);
self.digits.bump(n);
self
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, From, IsVariant, TryUnwrap, Unwrap)]
#[unwrap(ref, ref_mut)]
#[try_unwrap(ref, ref_mut)]
#[non_exhaustive]
pub enum HexEscapeError<Char = char, O = usize> {
Incomplete(IncompleteHexEscape<O>),
Malformed(MalformedHexEscape<Char, O>),
}
impl<Char, O> core::fmt::Display for HexEscapeError<Char, O>
where
Char: DisplayHuman,
O: core::fmt::Display,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::Incomplete(err) => err.fmt(f),
Self::Malformed(malformed) => malformed.fmt(f),
}
}
}
impl<Char, O> core::error::Error for HexEscapeError<Char, O>
where
Char: DisplayHuman + core::fmt::Debug + 'static,
O: core::fmt::Debug + core::fmt::Display + 'static,
{
fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
match self {
Self::Incomplete(err) => Some(err),
Self::Malformed(err) => Some(err),
}
}
}
impl<Char, O> HexEscapeError<Char, O> {
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn incomplete(span: SimpleSpan<O>) -> Self {
Self::Incomplete(IncompleteHexEscape::new(span))
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn malformed(digits: InvalidHexEscapeDigits<Char, O>, span: SimpleSpan<O>) -> Self {
Self::Malformed(MalformedHexEscape::new(digits, span))
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn span(&self) -> SimpleSpan<O>
where
O: Copy,
{
match self {
Self::Incomplete(incomplete) => incomplete.span(),
Self::Malformed(malformed) => malformed.span(),
}
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn bump(&mut self, n: &O) -> &mut Self
where
O: for<'a> AddAssign<&'a O> + Clone,
{
match self {
Self::Incomplete(incomplete) => {
incomplete.bump(n);
}
Self::Malformed(malformed) => {
malformed.bump(n);
}
}
self
}
}