use core::fmt::Debug;
use core::marker::PhantomData;
use core::ops::RangeBounds;
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::neu::EmptyCond;
use crate::neu::calc_length;
use crate::regex::Regex;
use crate::regex::impl_not_for_regex;
use crate::span::Span;
use super::CRange;
use super::Condition;
use super::Neu;
use super::NeuCond;
pub struct Between<const M: usize, const N: usize, C, U, I = EmptyCond> {
unit: U,
cond: I,
marker: PhantomData<C>,
}
impl<const M: usize, const N: usize, C, U, I> core::ops::Not for Between<M, N, C, U, I> {
type Output = crate::regex::Assert<Self>;
fn not(self) -> Self::Output {
crate::regex::not(self)
}
}
impl<const M: usize, const N: usize, C, U, I> Debug for Between<M, N, C, U, I>
where
I: Debug,
U: Debug,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("Between")
.field("unit", &self.unit)
.field("cond", &self.cond)
.finish()
}
}
impl<const M: usize, const N: usize, C, U, I> Clone for Between<M, N, C, U, I>
where
I: Clone,
U: Clone,
{
fn clone(&self) -> Self {
Self {
unit: self.unit.clone(),
cond: self.cond.clone(),
marker: self.marker,
}
}
}
impl<const M: usize, const N: usize, C, U, I> Copy for Between<M, N, C, U, I>
where
I: Copy,
U: Copy,
{
}
impl<const M: usize, const N: usize, C, U, I> Between<M, N, C, U, I> {
pub const fn new(unit: U, cond: I) -> Self {
Self {
unit,
cond,
marker: PhantomData,
}
}
pub const fn unit(&self) -> &U {
&self.unit
}
pub const fn unit_mut(&mut self) -> &mut U {
&mut self.unit
}
pub fn set_unit(&mut self, unit: U) -> &mut Self {
self.unit = unit;
self
}
}
impl<'a, const M: usize, const N: usize, C, U, I> Condition<'a, C> for Between<M, N, C, U, I>
where
U: Neu<C::Item>,
I: NeuCond<'a, C>,
C: Context<'a>,
{
type Out<F> = Between<M, N, C, U, F>;
fn set_cond<F>(self, cond: F) -> Self::Out<F>
where
F: NeuCond<'a, C>,
{
Between::<M, N, C, U, F>::new(self.unit, cond)
}
}
impl<'a, const M: usize, const N: usize, U, C, O, I, H> Ctor<C, O, H> for Between<M, N, C, U, I>
where
U: Neu<C::Item>,
I: NeuCond<'a, C>,
C: Match<'a>,
H: Handler<C, Out = O>,
{
#[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, const M: usize, const N: usize, U, C, I> Regex<C> for Between<M, N, C, U, I>
where
U: Neu<C::Item>,
I: NeuCond<'a, C>,
C: Context<'a>,
{
#[inline(always)]
fn try_parse(&self, ctx: &mut C) -> Result<Span, crate::err::Error> {
let mut cnt = 0;
let mut beg = None;
let mut end = None;
let mut ret = Err(Error::Between);
let mut iter = ctx.peek()?;
let remaining_len = ctx.len() - ctx.offset();
let range = M..N;
crate::debug_regex_beg!("Between", &range, ctx.offset());
if remaining_len >= M * self.unit.min_length() {
while cnt < N {
if let Some(pair) = iter.next() {
if self.unit.is_match(&pair.1) && self.cond.check(ctx, &pair)? {
cnt += 1;
if beg.is_none() {
beg = Some(pair.0);
}
continue;
} else {
end = Some(pair);
}
}
break;
}
if cnt >= M {
let end = end.or_else(|| iter.next());
let len = calc_length(beg, end.map(|v| v.0), remaining_len);
ret = Ok(new_span_inc(ctx, len));
}
}
crate::debug_regex_reval!("Between", cnt, ret)
}
}
pub struct Times<C, U, I = EmptyCond> {
unit: U,
cond: I,
range: CRange<usize>,
marker: PhantomData<C>,
}
impl_not_for_regex!(Times<C, U, I>);
impl<C, U, I> Debug for Times<C, U, I>
where
U: Debug,
I: Debug,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("Times")
.field("unit", &self.unit)
.field("cond", &self.cond)
.field("range", &self.range)
.finish()
}
}
impl<C, U, I> Clone for Times<C, U, I>
where
U: Clone,
I: Clone,
{
fn clone(&self) -> Self {
Self {
unit: self.unit.clone(),
cond: self.cond.clone(),
range: self.range,
marker: self.marker,
}
}
}
impl<C, U, I> Copy for Times<C, U, I>
where
U: Copy,
I: Copy,
{
}
impl<C, U, I> Times<C, U, I> {
pub const fn new(unit: U, range: CRange<usize>, cond: I) -> Self {
Self {
unit,
range,
cond,
marker: PhantomData,
}
}
pub const fn unit(&self) -> &U {
&self.unit
}
pub const fn range(&self) -> &CRange<usize> {
&self.range
}
pub const fn unit_mut(&mut self) -> &mut U {
&mut self.unit
}
pub const fn range_mut(&mut self) -> &mut CRange<usize> {
&mut self.range
}
pub fn set_unit(&mut self, unit: U) -> &mut Self {
self.unit = unit;
self
}
pub fn set_range(&mut self, range: impl Into<CRange<usize>>) -> &mut Self {
self.range = range.into();
self
}
}
impl<'a, C, U, I> Condition<'a, C> for Times<C, U, I>
where
U: Neu<C::Item>,
I: NeuCond<'a, C>,
C: Context<'a>,
{
type Out<F> = Times<C, U, F>;
fn set_cond<F>(self, cond: F) -> Self::Out<F>
where
F: NeuCond<'a, C>,
{
Times::<C, U, F>::new(self.unit, self.range, cond)
}
}
impl<'a, U, C, O, I, H> Ctor<C, O, H> for Times<C, U, I>
where
U: Neu<C::Item>,
I: NeuCond<'a, C>,
C: Match<'a>,
H: Handler<C, Out = O>,
{
#[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, U, C, I> Regex<C> for Times<C, U, I>
where
U: Neu<C::Item>,
I: NeuCond<'a, C>,
C: Context<'a>,
{
#[inline(always)]
fn try_parse(&self, ctx: &mut C) -> Result<Span, crate::err::Error> {
let mut cnt = 0;
let mut beg = None;
let mut end = None;
let mut ret = Err(Error::Times);
let mut iter = ctx.peek()?;
let remaining_len = ctx.len() - ctx.offset();
fn bound_checker(max: Option<usize>) -> impl Fn(usize) -> bool {
move |val| max.map(|max| val < max).unwrap_or(true)
}
let cond = bound_checker(match self.range.end_bound() {
core::ops::Bound::Included(max) => Some(*max),
core::ops::Bound::Excluded(max) => Some(max.saturating_sub(1)),
core::ops::Bound::Unbounded => None,
});
let min_length = || match self.range.start_bound() {
core::ops::Bound::Included(max) => max * self.unit.min_length(),
core::ops::Bound::Excluded(max) => max.saturating_sub(1) * self.unit.min_length(),
core::ops::Bound::Unbounded => 0,
};
crate::debug_regex_beg!("Times", self.range, ctx.offset());
if remaining_len >= min_length() {
while cond(cnt) {
if let Some(pair) = iter.next() {
if self.unit.is_match(&pair.1) && self.cond.check(ctx, &pair)? {
cnt += 1;
if beg.is_none() {
beg = Some(pair.0);
}
continue;
} else {
end = Some(pair);
}
}
break;
}
if self.range.contains(&cnt) {
let end = end.or_else(|| iter.next());
let len = calc_length(beg, end.map(|v| v.0), remaining_len);
ret = Ok(new_span_inc(ctx, len));
}
}
crate::debug_regex_reval!("Times", cnt, ret)
}
}