mod fold;
mod repeat;
mod sep;
pub use repeat::*;
pub use sep::*;
use crate::{
action::{Action, Input, Output},
combinator::Combinator,
digest::Digest,
instant::Instant,
};
use std::{
ops::{self, RangeFrom},
slice::SliceIndex,
};
#[derive(Debug, Clone, Copy)]
pub struct Mul<Lhs, Rhs, Sep = NoSep<Lhs>, Init = fn(), Fold = fn((), ())> {
lhs: Lhs,
rhs: Rhs,
sep: Sep,
init: Init,
fold: Fold,
}
impl<Lhs, Rhs> Mul<Lhs, Rhs> {
#[inline]
const fn new(lhs: Lhs, rhs: Rhs) -> Self {
Self {
lhs,
rhs,
sep: NoSep::new(),
init: || (),
fold: |_, _| (),
}
}
}
impl<Lhs: Action, Rhs: Repeat> ops::Mul<Rhs> for Combinator<Lhs> {
type Output = Combinator<Mul<Lhs, Rhs, NoSep<Lhs>>>;
#[inline]
fn mul(self, rhs: Rhs) -> Self::Output {
Self::Output::new(Mul::new(self.action, rhs))
}
}
impl<Lhs: Action, const N: usize> ops::Mul<[Lhs::Value; N]> for Combinator<Lhs> {
type Output = Combinator<Mul<Lhs, [Lhs::Value; N], NoSep<Lhs>>>;
#[inline]
fn mul(self, rhs: [Lhs::Value; N]) -> Self::Output {
Self::Output::new(Mul::new(self.action, rhs))
}
}
unsafe impl<
Lhs: Action<Text: Digest>,
Rhs: Repeat,
Sep: Action<Text = Lhs::Text, State = Lhs::State, Heap = Lhs::Heap>,
Acc,
Init: Fn() -> Acc,
Fold: Fn(Acc, Lhs::Value) -> Acc,
> Action for Mul<Lhs, Rhs, Sep, Init, Fold>
where
RangeFrom<usize>: SliceIndex<Lhs::Text, Output = Lhs::Text>,
{
type Text = Lhs::Text;
type State = Lhs::State;
type Heap = Lhs::Heap;
type Value = Acc;
#[inline]
fn exec(
&self,
mut input: Input<&Instant<&Self::Text>, &mut Self::State, &mut Self::Heap>,
) -> Option<Output<Self::Value>> {
let mut repeated = 0;
let mut output = Output {
value: (self.init)(),
digested: 0,
};
let mut digested_with_sep = 0;
while unsafe { self.rhs.validate(repeated) } {
let Some(value_output) = self.lhs.exec(
input.reborrow_with(&unsafe { input.instant.to_digested_unchecked(digested_with_sep) }),
) else {
break;
};
repeated += 1;
output.value = (self.fold)(output.value, value_output.value);
debug_assert!(usize::MAX - digested_with_sep > value_output.digested);
output.digested = unsafe { digested_with_sep.unchecked_add(value_output.digested) };
let Some(sep_output) = self.sep.exec(
input.reborrow_with(&unsafe { input.instant.to_digested_unchecked(output.digested) }),
) else {
break;
};
debug_assert!(usize::MAX - output.digested > sep_output.digested);
digested_with_sep = unsafe { output.digested.unchecked_add(sep_output.digested) };
}
self.rhs.accept(repeated).then_some(output)
}
}
unsafe impl<
Lhs: Action<Text: Digest, Value: Clone>,
const N: usize,
Sep: Action<Text = Lhs::Text, State = Lhs::State, Heap = Lhs::Heap>,
> Action for Mul<Lhs, [Lhs::Value; N], Sep>
where
RangeFrom<usize>: SliceIndex<Lhs::Text, Output = Lhs::Text>,
{
type Text = Lhs::Text;
type State = Lhs::State;
type Heap = Lhs::Heap;
type Value = [Lhs::Value; N];
#[inline]
fn exec(
&self,
mut input: Input<&Instant<&Self::Text>, &mut Self::State, &mut Self::Heap>,
) -> Option<Output<Self::Value>> {
let mut output: Output<[<Lhs as Action>::Value; N]> = Output {
value: self.rhs.clone(),
digested: 0,
};
let mut digested_with_sep = 0;
for i in 0..N {
let value_output = self.lhs.exec(
input.reborrow_with(&unsafe { input.instant.to_digested_unchecked(digested_with_sep) }),
)?;
debug_assert!(i < N);
*unsafe { output.value.get_unchecked_mut(i) } = value_output.value;
debug_assert!(usize::MAX - digested_with_sep > value_output.digested);
output.digested = unsafe { digested_with_sep.unchecked_add(value_output.digested) };
if unsafe { i.unchecked_add(1) } == N {
break;
}
let sep_output = self.sep.exec(
input.reborrow_with(&unsafe { input.instant.to_digested_unchecked(output.digested) }),
)?;
debug_assert!(usize::MAX - output.digested > sep_output.digested);
digested_with_sep = unsafe { output.digested.unchecked_add(sep_output.digested) };
}
Some(output)
}
}
#[cfg(test)]
mod tests {
use crate::{
action::{Action, Input, Output},
combinator::{bytes, take},
digest::Digest,
instant::Instant,
};
use std::{fmt::Debug, ops::RangeFrom, slice::SliceIndex};
fn helper<Text: ?Sized + Digest>(
action: impl Action<Text = Text, State = (), Heap = (), Value = ()>,
input: &Text,
expected: Option<usize>,
) where
RangeFrom<usize>: SliceIndex<Text, Output = Text>,
{
assert_eq!(
action.exec(Input {
instant: &Instant::new(input),
state: &mut (),
heap: &mut ()
}),
expected.map(|digested| Output {
value: (),
digested,
})
)
}
#[test]
fn combinator_mul_usize() {
let accepter = || take(1);
let accepter_b = || bytes::take(1);
let rejecter = || take(0).reject(|_| true);
let rejecter_b = || bytes::take(0).reject(|_| true);
helper(accepter() * 3, "1234", Some(3));
helper(accepter_b() * 3, b"1234", Some(3));
helper(accepter() * 3, "12", None);
helper(accepter_b() * 3, b"12", None);
helper(rejecter() * 3, "123", None);
helper(rejecter_b() * 3, b"123", None);
helper(accepter() * 0, "123", Some(0));
helper(accepter_b() * 0, b"123", Some(0));
helper(rejecter() * 0, "123", Some(0));
helper(rejecter_b() * 0, b"123", Some(0));
}
#[test]
fn combinator_mul_range() {
let accepter = || take(1);
let accepter_b = || bytes::take(1);
let rejecter = || take(0).reject(|_| true);
let rejecter_b = || bytes::take(0).reject(|_| true);
helper(accepter() * (2..4), "1234", Some(3));
helper(accepter_b() * (2..4), b"1234", Some(3));
helper(accepter() * (2..4), "1", None);
helper(accepter_b() * (2..4), b"1", None);
helper(rejecter() * (2..4), "123", None);
helper(rejecter_b() * (2..4), b"123", None);
helper(accepter() * (0..1), "123", Some(0));
helper(accepter_b() * (0..1), b"123", Some(0));
helper(rejecter() * (0..1), "123", Some(0));
helper(rejecter_b() * (0..1), b"123", Some(0));
}
#[test]
fn combinator_mul_range_from() {
let accepter = || take(1);
let accepter_b = || bytes::take(1);
let rejecter = || take(0).reject(|_| true);
let rejecter_b = || bytes::take(0).reject(|_| true);
helper(accepter() * (2..), "1234", Some(4));
helper(accepter_b() * (2..), b"1234", Some(4));
helper(accepter() * (2..), "1", None);
helper(accepter_b() * (2..), b"1", None);
helper(rejecter() * (2..), "123", None);
helper(rejecter_b() * (2..), b"123", None);
helper(rejecter() * (0..), "123", Some(0));
helper(rejecter_b() * (0..), b"123", Some(0));
}
#[test]
fn combinator_mul_range_full() {
let accepter = || take(1);
let accepter_b = || bytes::take(1);
let rejecter = || take(0).reject(|_| true);
let rejecter_b = || bytes::take(0).reject(|_| true);
helper(accepter() * (..), "1234", Some(4));
helper(accepter_b() * (..), b"1234", Some(4));
helper(rejecter() * (..), "123", Some(0));
helper(rejecter_b() * (..), b"123", Some(0));
}
#[test]
fn combinator_mul_range_inclusive() {
let accepter = || take(1);
let accepter_b = || bytes::take(1);
let rejecter = || take(0).reject(|_| true);
let rejecter_b = || bytes::take(0).reject(|_| true);
helper(accepter() * (2..=3), "1234", Some(3));
helper(accepter_b() * (2..=3), b"1234", Some(3));
helper(accepter() * (2..=3), "1", None);
helper(accepter_b() * (2..=3), b"1", None);
helper(rejecter() * (2..=3), "123", None);
helper(rejecter_b() * (2..=3), b"123", None);
helper(accepter() * (0..=0), "123", Some(0));
helper(accepter_b() * (0..=0), b"123", Some(0));
helper(rejecter() * (0..=0), "123", Some(0));
helper(rejecter_b() * (0..=0), b"123", Some(0));
}
#[test]
fn combinator_mul_range_to() {
let accepter = || take(1);
let accepter_b = || bytes::take(1);
let rejecter = || take(0).reject(|_| true);
let rejecter_b = || bytes::take(0).reject(|_| true);
helper(accepter() * (..4), "1234", Some(3));
helper(accepter_b() * (..4), b"1234", Some(3));
helper(accepter() * (..1), "123", Some(0));
helper(accepter_b() * (..1), b"123", Some(0));
helper(rejecter() * (..1), "123", Some(0));
helper(rejecter_b() * (..1), b"123", Some(0));
}
#[test]
fn combinator_mul_range_to_inclusive() {
let accepter = || take(1);
let accepter_b = || bytes::take(1);
let rejecter = || take(0).reject(|_| true);
let rejecter_b = || bytes::take(0).reject(|_| true);
helper(accepter() * (2..=3), "1234", Some(3));
helper(accepter_b() * (2..=3), b"1234", Some(3));
helper(accepter() * (2..=3), "1", None);
helper(accepter_b() * (2..=3), b"1", None);
helper(rejecter() * (2..=3), "123", None);
helper(rejecter_b() * (2..=3), b"123", None);
helper(accepter() * (0..=0), "123", Some(0));
helper(accepter_b() * (0..=0), b"123", Some(0));
helper(rejecter() * (0..=0), "123", Some(0));
helper(rejecter_b() * (0..=0), b"123", Some(0));
}
#[test]
fn combinator_mul_array() {
fn helper<Text: ?Sized + Digest, Value: PartialEq + Debug>(
action: impl Action<Text = Text, State = (), Heap = (), Value = Value>,
input: &Text,
expected: Option<Output<Value>>,
) where
RangeFrom<usize>: SliceIndex<Text, Output = Text>,
{
assert_eq!(
action.exec(Input {
instant: &Instant::new(input),
state: &mut (),
heap: &mut ()
}),
expected
)
}
let accepter = || take(1).select(|accepted| accepted.content().as_bytes()[0] - b'0');
let accepter_b = || bytes::take(1).select(|accepted| accepted.content()[0] - b'0');
let rejecter = || accepter().reject(|_| true);
let rejecter_b = || accepter_b().reject(|_| true);
helper(
accepter() * [0; 3],
"123",
Some(Output {
value: [1, 2, 3],
digested: 3,
}),
);
helper(
accepter_b() * [0; 3],
b"123",
Some(Output {
value: [1, 2, 3],
digested: 3,
}),
);
helper(accepter() * [0; 3], "12", None);
helper(accepter_b() * [0; 3], b"12", None);
helper(rejecter() * [0; 3], "123", None);
helper(rejecter_b() * [0; 3], b"123", None);
helper(
accepter() * [0; 0],
"123",
Some(Output {
value: [],
digested: 0,
}),
);
helper(
accepter_b() * [0; 0],
b"123",
Some(Output {
value: [],
digested: 0,
}),
);
helper(
rejecter_b() * [0; 0],
b"123",
Some(Output {
value: [],
digested: 0,
}),
);
}
}