use crate::ctor::Ctor;
use crate::ctor::Handler;
use crate::ctx::Context;
use crate::ctx::Match;
use crate::ctx::new_span_inc;
use crate::err::Error;
use crate::regex::Regex;
use crate::span::Span;
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Literal<'a, T: ?Sized> {
literal: &'a T,
}
impl<'a, T: ?Sized> Clone for Literal<'a, T> {
fn clone(&self) -> Self {
*self
}
}
impl<'a, T: ?Sized> Copy for Literal<'a, T> {}
impl<'a, T: ?Sized> core::ops::Not for Literal<'a, T> {
type Output = crate::regex::Assert<Self>;
fn not(self) -> Self::Output {
crate::regex::not(self)
}
}
impl<'a, T: ?Sized> Literal<'a, T> {
pub const fn new(literal: &'a T) -> Self {
Self { literal }
}
}
impl<'a, C, O, T, H> Ctor<C, O, H> for Literal<'_, T>
where
T: ?Sized + LiteralTy,
H: Handler<C, Out = O>,
C: Match<'a, Orig<'a> = <T as LiteralTy>::Orig<'a>>,
{
#[inline(always)]
fn construct(&self, ctx: &mut C, func: &mut H) -> Result<O, Error> {
let ret = ctx.try_mat(self)?;
func.invoke(ctx, &ret).map_err(Into::into)
}
}
impl<'a, C, T> Regex<C> for Literal<'_, T>
where
T: ?Sized + LiteralTy,
C: Context<'a, Orig<'a> = <T as LiteralTy>::Orig<'a>>,
{
#[inline(always)]
fn try_parse(&self, ctx: &mut C) -> Result<Span, crate::err::Error> {
let mut ret = Err(Error::Literal);
let slice_len = self.literal.length();
let remaining_len = ctx.len() - ctx.offset();
crate::debug_regex_beg!("Literal", ctx.offset());
if remaining_len >= slice_len && self.literal.prefix_of(&ctx.orig()?) {
ret = Ok(new_span_inc(ctx, slice_len));
}
crate::debug_regex_reval!("Literal", ret)
}
}
pub trait LiteralTy {
type Orig<'a>;
fn length(&self) -> usize;
fn prefix_of<'a>(&self, other: &Self::Orig<'a>) -> bool;
}
impl LiteralTy for str {
type Orig<'a> = &'a str;
fn length(&self) -> usize {
str::len(self)
}
fn prefix_of<'a>(&self, other: &Self::Orig<'a>) -> bool {
str::starts_with(other, self)
}
}
#[cfg(feature = "alloc")]
impl LiteralTy for crate::alloc::String {
type Orig<'a> = &'a str;
fn length(&self) -> usize {
str::len(self)
}
fn prefix_of<'a>(&self, other: &Self::Orig<'a>) -> bool {
str::starts_with(other, self.as_str())
}
}
impl LiteralTy for [u8] {
type Orig<'a> = &'a [u8];
fn length(&self) -> usize {
<[u8]>::len(self)
}
fn prefix_of<'a>(&self, other: &Self::Orig<'a>) -> bool {
<[u8]>::starts_with(other, self)
}
}
impl<const N: usize> LiteralTy for [u8; N] {
type Orig<'a> = &'a [u8];
fn length(&self) -> usize {
<[u8]>::len(self)
}
fn prefix_of<'a>(&self, other: &Self::Orig<'a>) -> bool {
<[u8]>::starts_with(other, self)
}
}
pub const fn literal<T: LiteralTy + ?Sized>(lit: &T) -> Literal<'_, T> {
Literal::new(lit)
}