use core::str::CharIndices;
use super::Context;
use super::PolicyCtx;
use super::PolicyMatch;
use super::Regex;
use super::Span;
use crate::ctx::Match;
use crate::err::Error;
use crate::iter::BytesIndices;
use crate::iter::IndexBySpan;
#[derive(Debug)]
pub struct RegexCtx<'a, T>
where
T: ?Sized,
{
dat: &'a T,
offset: usize,
}
impl<T> Clone for RegexCtx<'_, T>
where
T: ?Sized,
{
fn clone(&self) -> Self {
*self
}
}
impl<T> Copy for RegexCtx<'_, T> where T: ?Sized {}
impl<'a, T> RegexCtx<'a, T>
where
T: ?Sized,
{
pub const fn new(dat: &'a T) -> Self {
Self { dat, offset: 0 }
}
pub const fn dat(&self) -> &'a T {
self.dat
}
pub const fn offset(&self) -> usize {
self.offset
}
pub fn with_dat(mut self, dat: &'a T) -> Self {
self.dat = dat;
self
}
pub fn with_offset(mut self, offset: usize) -> Self {
self.offset = offset;
self
}
pub fn reset_with(&mut self, dat: &'a T) -> &mut Self {
self.dat = dat;
self.offset = 0;
self
}
pub fn reset(&mut self) -> &mut Self {
self.offset = 0;
self
}
#[cfg(feature = "alloc")]
pub fn span_storer(&self, capacity: usize) -> crate::span::VecStorer {
crate::span::VecStorer::new(capacity)
}
pub fn with<F, R>(dat: &'a T, mut func: F) -> R
where
F: FnMut(Self) -> R,
{
let ctx = Self::new(dat);
func(ctx)
}
}
impl<T> RegexCtx<'_, T>
where
T: ?Sized,
{
pub const fn skip_before<R>(self, regex: R) -> PolicyCtx<Self, R> {
PolicyCtx { inner: self, regex }
}
}
impl<'a> RegexCtx<'a, [u8]> {
pub const fn skip_ascii_whitespace(
self,
) -> PolicyCtx<Self, crate::neu::Many0<Self, crate::neu::AsciiWhiteSpace<u8>, u8>> {
use crate::neu;
self.skip_before(neu::Many0::new(neu::ascii_whitespace(), neu::EmptyCond))
}
}
impl<'a> RegexCtx<'a, str> {
pub const fn skip_ascii_whitespace(
self,
) -> PolicyCtx<Self, crate::neu::Many0<Self, crate::neu::AsciiWhiteSpace<char>, char>> {
use crate::neu;
self.skip_before(neu::Many0::new(neu::ascii_whitespace(), neu::EmptyCond))
}
}
impl<'a> RegexCtx<'a, str> {
pub const fn skip_whitespace(
self,
) -> PolicyCtx<Self, crate::neu::Many0<Self, crate::neu::WhiteSpace, char>> {
use crate::neu;
self.skip_before(neu::Many0::new(neu::whitespace(), neu::EmptyCond))
}
}
impl<'a> Context<'a> for RegexCtx<'a, [u8]> {
type Orig<'b> = &'b [u8];
type Item = u8;
type Iter<'b> = BytesIndices<'b, u8>;
fn len(&self) -> usize {
self.dat.len()
}
fn offset(&self) -> usize {
self.offset
}
fn set_offset(&mut self, offset: usize) -> &mut Self {
self.offset = offset;
crate::neure_debug!("RegexCtx: set offset => {}", self.offset);
self
}
fn inc(&mut self, offset: usize) -> &mut Self {
self.offset += offset;
crate::neure_debug!("RegexCtx: + {} => {}", offset, self.offset);
self
}
fn dec(&mut self, offset: usize) -> &mut Self {
self.offset -= offset;
crate::neure_debug!("RegexCtx: - {} => {}", offset, self.offset);
self
}
fn peek_at(&self, offset: usize) -> Result<Self::Iter<'a>, Error> {
Ok(BytesIndices::new(self.orig_at(offset)?))
}
fn orig_sub(&self, offset: usize, len: usize) -> Result<Self::Orig<'a>, Error> {
self.dat
.get(offset..(offset + len))
.ok_or(Error::OutOfBound)
}
fn clone_at(&self, offset: usize) -> Result<Self, Error> {
self.orig_at(offset).map(RegexCtx::new)
}
}
impl<'a> Context<'a> for RegexCtx<'a, str> {
type Orig<'b> = &'b str;
type Item = char;
type Iter<'b> = CharIndices<'b>;
fn len(&self) -> usize {
self.dat.len()
}
fn offset(&self) -> usize {
self.offset
}
fn set_offset(&mut self, offset: usize) -> &mut Self {
self.offset = offset;
crate::neure_debug!("RegexCtx: set offset = {}", self.offset);
self
}
fn inc(&mut self, offset: usize) -> &mut Self {
self.offset += offset;
crate::neure_debug!("RegexCtx: + {} => {}", offset, self.offset);
self
}
fn dec(&mut self, offset: usize) -> &mut Self {
self.offset -= offset;
crate::neure_debug!("RegexCtx: - {} => {}", offset, self.offset);
self
}
fn orig_at(&self, offset: usize) -> Result<Self::Orig<'a>, Error> {
self.dat.get(offset..).ok_or(Error::OutOfBound)
}
fn peek_at(&self, offset: usize) -> Result<Self::Iter<'a>, Error> {
Ok(self.orig_at(offset)?.char_indices())
}
fn orig_sub(&self, offset: usize, len: usize) -> Result<Self::Orig<'a>, Error> {
self.dat
.get(offset..(offset + len))
.ok_or(Error::OutOfBound)
}
fn clone_at(&self, offset: usize) -> Result<Self, Error> {
self.orig_at(offset).map(RegexCtx::new)
}
}
impl<'a, T> Match<'a> for RegexCtx<'a, T>
where
T: ?Sized,
Self: Context<'a>,
{
fn try_mat<Pat>(&mut self, pat: &Pat) -> Result<Span, Error>
where
Pat: Regex<RegexCtx<'a, T>> + ?Sized,
{
self.try_mat_before(pat, &|_: &mut Self| Ok(Span::default()))
}
}
impl<'a, T> PolicyMatch<'a> for RegexCtx<'a, T>
where
T: ?Sized,
Self: Context<'a>,
{
fn try_mat_policy<P, B, A>(&mut self, pat: &P, before: &B, after: &A) -> Result<Span, Error>
where
P: Regex<RegexCtx<'a, T>> + ?Sized,
B: Regex<RegexCtx<'a, T>> + ?Sized,
A: Regex<RegexCtx<'a, T>> + ?Sized,
{
before.try_parse(self)?;
let ret = pat.try_parse(self)?;
after.try_parse(self)?;
Ok(ret)
}
}
impl<'a> IndexBySpan for RegexCtx<'a, [u8]> {
type Output = [u8];
fn get_by_span(&self, span: &Span) -> Option<&Self::Output> {
span.orig(self).ok()
}
}
impl<'a> IndexBySpan for RegexCtx<'a, str> {
type Output = str;
fn get_by_span(&self, span: &Span) -> Option<&Self::Output> {
span.orig(self).ok()
}
}