use super::{create_closure_decorator, create_simple_decorator, Accepted};
use crate::{
action::Input,
combinator::{Action, Combinator, Output},
digest::Digest,
instant::Instant,
};
create_closure_decorator!(When, "See [`Combinator::when`].");
create_closure_decorator!(Prevent, "See [`Combinator::prevent`].");
create_closure_decorator!(Reject, "See [`Combinator::reject`].");
create_simple_decorator!(Optional, "See [`Combinator::optional`].");
create_simple_decorator!(Boundary, "See [`Combinator::boundary`].");
unsafe impl<T: Action, D: Fn(Input<&Instant<&T::Text>, &mut T::State, &mut T::Heap>) -> bool> Action
for When<T, D>
{
type Text = T::Text;
type State = T::State;
type Heap = T::Heap;
type Value = T::Value;
#[inline]
fn exec(
&self,
mut input: Input<&Instant<&Self::Text>, &mut Self::State, &mut Self::Heap>,
) -> Option<Output<Self::Value>> {
if (self.inner)(input.reborrow()) {
self.action.exec(input)
} else {
None
}
}
}
unsafe impl<T: Action, D: Fn(Input<&Instant<&T::Text>, &mut T::State, &mut T::Heap>) -> bool> Action
for Prevent<T, D>
{
type Text = T::Text;
type State = T::State;
type Heap = T::Heap;
type Value = T::Value;
#[inline]
fn exec(
&self,
mut input: Input<&Instant<&Self::Text>, &mut Self::State, &mut Self::Heap>,
) -> Option<Output<Self::Value>> {
if !(self.inner)(input.reborrow()) {
self.action.exec(input)
} else {
None
}
}
}
unsafe impl<
T: Action<Text: Digest>,
D: Fn(Accepted<&Instant<&T::Text>, &mut T::State, &mut T::Heap, &T::Value>) -> bool,
> Action for Reject<T, D>
{
type Text = T::Text;
type State = T::State;
type Heap = T::Heap;
type Value = T::Value;
#[inline]
fn exec(
&self,
mut input: Input<&Instant<&Self::Text>, &mut Self::State, &mut Self::Heap>,
) -> Option<Output<Self::Value>> {
self.action.exec(input.reborrow()).and_then(|output| {
if (self.inner)(unsafe {
Accepted::new_unchecked(input.instant, output.as_ref(), input.state, input.heap)
}) {
None
} else {
output.into()
}
})
}
}
unsafe impl<T: Action<Value: Default>> Action for Optional<T> {
type Text = T::Text;
type State = T::State;
type Heap = T::Heap;
type Value = T::Value;
#[inline]
fn exec(
&self,
input: Input<&Instant<&Self::Text>, &mut Self::State, &mut Self::Heap>,
) -> Option<Output<Self::Value>> {
Some(self.action.exec(input).unwrap_or_else(|| Output {
value: Default::default(),
digested: 0,
}))
}
}
unsafe impl<T: Action<Text = str>> Action for Boundary<T> {
type Text = T::Text;
type State = T::State;
type Heap = T::Heap;
type Value = T::Value;
#[inline]
fn exec(
&self,
input: Input<&Instant<&Self::Text>, &mut Self::State, &mut Self::Heap>,
) -> Option<Output<Self::Value>> {
let rest = input.instant.rest();
self.action.exec(input).and_then(|output| {
unsafe { rest.get_unchecked(output.digested..) }
.chars()
.next()
.is_none_or(|c| !c.is_alphanumeric() && c != '_')
.then_some(output)
})
}
}
impl<T> Combinator<T> {
#[inline]
pub fn when<F: Fn(Input<&Instant<&T::Text>, &mut T::State, &mut T::Heap>) -> bool>(
self,
condition: F,
) -> Combinator<When<T, F>>
where
T: Action,
{
Combinator::new(When::new(self.action, condition))
}
#[inline]
pub fn prevent<F: Fn(Input<&Instant<&T::Text>, &mut T::State, &mut T::Heap>) -> bool>(
self,
preventer: F,
) -> Combinator<Prevent<T, F>>
where
T: Action,
{
Combinator::new(Prevent::new(self.action, preventer))
}
#[inline]
pub fn reject<
F: Fn(Accepted<&Instant<&T::Text>, &mut T::State, &mut T::Heap, &T::Value>) -> bool,
>(
self,
rejecter: F,
) -> Combinator<Reject<T, F>>
where
T: Action,
{
Combinator::new(Reject::new(self.action, rejecter))
}
#[inline]
pub fn optional(self) -> Combinator<Optional<T>> {
Combinator::new(Optional::new(self.action))
}
#[inline]
pub fn boundary(self) -> Combinator<Boundary<T>> {
Combinator::new(Boundary::new(self.action))
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{contextual, digest::Digest, instant::Instant};
use std::{fmt::Debug, ops::RangeFrom, slice::SliceIndex};
fn helper<Text: ?Sized + Digest>(
action: impl Action<Text = Text, State = bool, Heap = (), Value = ()>,
input: &Text,
state: &mut bool,
digested: Option<usize>,
) where
RangeFrom<usize>: SliceIndex<Text, Output = Text>,
{
assert_eq!(
action
.exec(Input {
instant: &Instant::new(input),
state,
heap: &mut ()
})
.map(|o| o.digested),
digested
)
}
contextual!(bool, ());
fn accepter(
) -> Combinator<impl Action<Text = str, State = bool, Heap = (), Value = ()> + Debug + Copy> {
wrap(|input| {
*input.state = true;
input.instant.accept(1)
})
}
fn accepter_bytes(
) -> Combinator<impl Action<Text = [u8], State = bool, Heap = (), Value = ()> + Debug + Copy> {
bytes::wrap(|input| {
*input.state = true;
input.instant.accept(1)
})
}
fn rejecter(
) -> Combinator<impl Action<Text = str, State = bool, Heap = (), Value = ()> + Debug + Copy> {
wrap(|input| {
*input.state = true;
None
})
}
fn rejecter_bytes(
) -> Combinator<impl Action<Text = [u8], State = bool, Heap = (), Value = ()> + Debug + Copy> {
bytes::wrap(|input| {
*input.state = true;
None
})
}
#[test]
fn combinator_when() {
let mut executed = false;
helper(accepter().when(|_| false), "123", &mut executed, None);
assert!(!executed);
let mut executed = false;
helper(
accepter_bytes().when(|_| false),
b"123",
&mut executed,
None,
);
assert!(!executed);
let mut executed = false;
helper(accepter().when(|_| true), "123", &mut executed, Some(1));
assert!(executed);
let mut executed = false;
helper(
accepter_bytes().when(|_| true),
b"123",
&mut executed,
Some(1),
);
assert!(executed);
let _ = format!("{:?}", accepter().when(|_| true));
let c = accepter().when(|_| true);
let _c = c;
let _c = c.clone();
}
#[test]
fn combinator_prevent() {
let mut executed = false;
helper(accepter().prevent(|_| true), "123", &mut executed, None);
assert!(!executed);
let mut executed = false;
helper(
accepter_bytes().prevent(|_| true),
b"123",
&mut executed,
None,
);
assert!(!executed);
let mut executed = false;
helper(accepter().prevent(|_| false), "123", &mut executed, Some(1));
assert!(executed);
let mut executed = false;
helper(
accepter_bytes().prevent(|_| false),
b"123",
&mut executed,
Some(1),
);
assert!(executed);
let _ = format!("{:?}", accepter().prevent(|_| true));
let c = accepter().prevent(|_| true);
let _c = c;
let _c = c.clone();
}
#[test]
fn combinator_reject() {
let mut executed = false;
helper(
accepter().reject(|accept| accept.content() != "1"),
"123",
&mut executed,
Some(1),
);
assert!(executed);
let mut executed = false;
helper(
accepter_bytes().reject(|accept| accept.content() != b"1"),
b"123",
&mut executed,
Some(1),
);
assert!(executed);
let mut executed = false;
helper(
accepter().reject(|accept| accept.content() == "1"),
"123",
&mut executed,
None,
);
assert!(executed);
let mut executed = false;
helper(
accepter_bytes().reject(|accept| accept.content() == b"1"),
b"123",
&mut executed,
None,
);
assert!(executed);
let _ = format!("{:?}", accepter().reject(|accept| accept.content() != "1"));
let c = accepter().reject(|accept| accept.content() != "1");
let _c = c;
let _c = c.clone();
}
#[test]
fn combinator_optional() {
let mut executed = false;
helper(accepter().optional(), "123", &mut executed, Some(1));
assert!(executed);
let mut executed = false;
helper(accepter_bytes().optional(), b"123", &mut executed, Some(1));
assert!(executed);
let mut executed = false;
helper(rejecter().optional(), "123", &mut executed, Some(0));
assert!(executed);
let mut executed = false;
helper(rejecter_bytes().optional(), b"123", &mut executed, Some(0));
assert!(executed);
let _ = format!("{:?}", accepter().optional());
let c = accepter().optional();
let _c = c;
let _c = c.clone();
}
#[test]
fn optional_can_be_the_last_one() {
let mut executed = false;
helper(accepter().optional(), "", &mut executed, Some(0));
assert!(executed);
let mut executed = false;
helper(accepter_bytes().optional(), b"", &mut executed, Some(0));
assert!(executed);
}
#[test]
fn combinator_boundary() {
let mut executed = false;
helper(accepter().boundary(), "1", &mut executed, Some(1));
assert!(executed);
let mut executed = false;
helper(accepter().boundary(), "1.", &mut executed, Some(1));
assert!(executed);
let mut executed = false;
helper(accepter().boundary(), "12", &mut executed, None);
assert!(executed);
let mut executed = false;
helper(accepter().boundary(), "1a", &mut executed, None);
assert!(executed);
let mut executed = false;
helper(accepter().boundary(), "1_", &mut executed, None);
assert!(executed);
let mut executed = false;
helper(accepter().boundary(), "1好", &mut executed, None);
assert!(executed);
let _ = format!("{:?}", accepter().boundary());
let c = accepter().boundary();
let _c = c;
let _c = c.clone();
}
}