use core::marker::PhantomData;
use derive_more::Display;
use crate::utils::Message;
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, Display)]
#[display("byte")]
pub struct FileHint;
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, Display)]
#[display("token")]
pub struct TokenHint;
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, Display)]
#[display("character")]
pub struct CharacterHint;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct UnexpectedEnd<Hint, O = usize, Lang: ?Sized = ()> {
offset: O,
name: Option<Message>,
hint: Hint,
_lang: PhantomData<Lang>,
}
impl<Hint, O, Lang> core::fmt::Display for UnexpectedEnd<Hint, O, Lang>
where
Hint: core::fmt::Display,
{
#[cfg_attr(not(tarpaulin), inline(always))]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self.name() {
Some(name) => write!(f, "unexpected end of {name}, expected {}", self.hint),
None => write!(f, "unexpected end, expected {}", self.hint),
}
}
}
impl<Hint, O, Lang> core::error::Error for UnexpectedEnd<Hint, O, Lang>
where
Hint: core::fmt::Debug + core::fmt::Display,
O: core::fmt::Debug,
Lang: core::fmt::Debug,
{
}
impl<O> UnexpectedEnd<FileHint, O> {
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn eof(offset: O) -> Self {
Self::maybe_name(offset, Some(Message::from_static("file")), FileHint)
}
}
impl<O, Lang: ?Sized> UnexpectedEnd<FileHint, O, Lang> {
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn eof_of(offset: O) -> Self {
Self::maybe_name_of(offset, Some(Message::from_static("file")), FileHint)
}
}
impl<O> UnexpectedEnd<TokenHint, O> {
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn eot(offset: O) -> Self {
Self::maybe_name(
offset,
Some(Message::from_static("token stream")),
TokenHint,
)
}
}
impl<O, Lang: ?Sized> UnexpectedEnd<TokenHint, O, Lang> {
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn eot_of(offset: O) -> Self {
Self::maybe_name_of(
offset,
Some(Message::from_static("token stream")),
TokenHint,
)
}
}
impl<O> UnexpectedEnd<CharacterHint, O> {
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn eos(offset: O) -> Self {
Self::maybe_name(offset, Some(Message::from_static("string")), CharacterHint)
}
}
impl<O, Lang: ?Sized> UnexpectedEnd<CharacterHint, O, Lang> {
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn eos_of(offset: O) -> Self {
Self::maybe_name_of(offset, Some(Message::from_static("string")), CharacterHint)
}
}
impl<Hint, O> UnexpectedEnd<Hint, O> {
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn new(offset: O, hint: Hint) -> Self {
Self::maybe_name(offset, None, hint)
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn maybe_name(offset: O, name: Option<Message>, hint: Hint) -> Self {
Self::maybe_name_of(offset, name, hint)
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn with_name(offset: O, name: Message, hint: Hint) -> Self {
Self::with_name_of(offset, name, hint)
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn with_hint(offset: O, hint: Hint) -> Self {
Self::with_hint_of(offset, hint)
}
}
impl<Hint, O, Lang: ?Sized> UnexpectedEnd<Hint, O, Lang> {
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn of(offset: O, hint: Hint) -> Self {
Self::maybe_name_of(offset, None, hint)
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn maybe_name_of(offset: O, name: Option<Message>, hint: Hint) -> Self {
Self {
offset,
name,
hint,
_lang: PhantomData,
}
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn with_name_of(offset: O, name: Message, hint: Hint) -> Self {
Self::maybe_name_of(offset, Some(name), hint)
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn with_hint_of(offset: O, hint: Hint) -> Self {
Self {
offset,
name: None,
hint,
_lang: PhantomData,
}
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn set_name(&mut self, name: impl Into<Message>) -> &mut Self {
self.name = Some(name.into());
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn update_name(&mut self, name: Option<impl Into<Message>>) -> &mut Self {
self.name = name.map(Into::into);
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn clear_name(&mut self) -> &mut Self {
self.name = None;
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn name(&self) -> Option<&str> {
match &self.name {
Some(name) => Some(name.as_str()),
None => None,
}
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn hint(&self) -> &Hint {
&self.hint
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn replace_hint(&mut self, new: Hint) -> Hint {
core::mem::replace(&mut self.hint, new)
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn map_hint<F, NewHint>(self, f: F) -> UnexpectedEnd<NewHint, O, Lang>
where
F: FnOnce(Hint) -> NewHint,
{
UnexpectedEnd {
offset: self.offset,
name: self.name,
hint: f(self.hint),
_lang: PhantomData,
}
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn reconstruct<F, NewHint>(
self,
name: Option<impl Into<Message>>,
f: F,
) -> UnexpectedEnd<NewHint, O, Lang>
where
F: FnOnce(Hint) -> NewHint,
{
UnexpectedEnd::maybe_name_of(self.offset, name.map(Into::into), f(self.hint))
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn reconstruct_with_name<F, NewHint>(
self,
name: impl Into<Message>,
f: F,
) -> UnexpectedEnd<NewHint, O, Lang>
where
F: FnOnce(Hint) -> NewHint,
{
UnexpectedEnd::with_name_of(self.offset, name.into(), f(self.hint))
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn reconstruct_without_name<F, NewHint>(self, f: F) -> UnexpectedEnd<NewHint, O, Lang>
where
F: FnOnce(Hint) -> NewHint,
{
UnexpectedEnd::of(self.offset, f(self.hint))
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn offset(&self) -> O
where
O: Copy,
{
self.offset
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn offset_ref(&self) -> &O {
&self.offset
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn offset_mut(&mut self) -> &mut O {
&mut self.offset
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn bump(&mut self, n: &O) -> &mut Self
where
O: for<'a> core::ops::AddAssign<&'a O>,
{
self.offset += n;
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn into_components(self) -> (O, Option<Message>, Hint) {
(self.offset, self.name, self.hint)
}
}
impl<Hint, O, Lang: ?Sized> From<UnexpectedEnd<Hint, O, Lang>> for () {
#[cfg_attr(not(tarpaulin), inline(always))]
fn from(_: UnexpectedEnd<Hint, O, Lang>) -> Self {}
}
pub type UnexpectedEof<O = usize, Lang = ()> = UnexpectedEnd<FileHint, O, Lang>;
pub type UnexpectedEot<O = usize, Lang = ()> = UnexpectedEnd<TokenHint, O, Lang>;
pub type UnexpectedEos<O = usize, Lang = ()> = UnexpectedEnd<CharacterHint, O, Lang>;
impl<Hint, O, Lang: ?Sized> From<(O, Hint)> for UnexpectedEnd<Hint, O, Lang> {
#[cfg_attr(not(tarpaulin), inline(always))]
fn from((offset, hint): (O, Hint)) -> Self {
Self::of(offset, hint)
}
}