use crate::bytesearch::{ByteArraySet, ByteSet, SmallArraySet, charset_contains};
use crate::cursor;
use crate::cursor::Direction;
use crate::indexing::{ElementType, InputIndexer};
use crate::insn::MAX_CHAR_SET_LENGTH;
use crate::matchers::CharProperties;
use crate::types::BracketContents;
pub trait SingleCharMatcher<Input: InputIndexer, Dir: Direction> {
fn matches(&self, input: &Input, dir: Dir, pos: &mut Input::Position) -> bool;
}
pub struct Char<Input: InputIndexer> {
pub c: Input::Element,
}
impl<Input: InputIndexer, Dir: Direction> SingleCharMatcher<Input, Dir> for Char<Input> {
#[inline(always)]
fn matches(&self, input: &Input, dir: Dir, pos: &mut Input::Position) -> bool {
match cursor::next(input, dir, pos) {
Some(c2) => c2 == self.c,
_ => false,
}
}
}
pub struct CharICase<Input: InputIndexer> {
pub c: Input::Element,
}
impl<Input: InputIndexer, Dir: Direction> SingleCharMatcher<Input, Dir> for CharICase<Input> {
#[inline(always)]
fn matches(&self, input: &Input, dir: Dir, pos: &mut Input::Position) -> bool {
match cursor::next(input, dir, pos) {
Some(c2) => c2 == self.c || input.fold(c2) == self.c,
_ => false,
}
}
}
pub struct CharSet<'a> {
pub chars: &'a [u32; MAX_CHAR_SET_LENGTH],
}
impl<Input: InputIndexer, Dir: Direction> SingleCharMatcher<Input, Dir> for CharSet<'_> {
#[inline(always)]
fn matches(&self, input: &Input, dir: Dir, pos: &mut Input::Position) -> bool {
match cursor::next(input, dir, pos) {
Some(c) => charset_contains(self.chars, c.as_u32()),
None => false,
}
}
}
pub struct Bracket<'a> {
pub bc: &'a BracketContents,
}
impl<Input: InputIndexer, Dir: Direction> SingleCharMatcher<Input, Dir> for Bracket<'_> {
#[inline(always)]
fn matches(&self, input: &Input, dir: Dir, pos: &mut Input::Position) -> bool {
match cursor::next(input, dir, pos) {
Some(c) => Input::CharProps::bracket(self.bc, c),
_ => false,
}
}
}
pub struct MatchAny {}
impl MatchAny {
pub fn new() -> Self {
Self {}
}
}
impl<Input: InputIndexer, Dir: Direction> SingleCharMatcher<Input, Dir> for MatchAny {
#[inline(always)]
fn matches(&self, input: &Input, dir: Dir, pos: &mut Input::Position) -> bool {
cursor::next(input, dir, pos).is_some()
}
}
pub struct MatchAnyExceptLineTerminator {}
impl MatchAnyExceptLineTerminator {
pub fn new() -> Self {
Self {}
}
}
impl<Input: InputIndexer, Dir: Direction> SingleCharMatcher<Input, Dir>
for MatchAnyExceptLineTerminator
{
#[inline(always)]
fn matches(&self, input: &Input, dir: Dir, pos: &mut Input::Position) -> bool {
match cursor::next(input, dir, pos) {
Some(c2) => !Input::CharProps::is_line_terminator(c2),
_ => false,
}
}
}
pub struct MatchByteSet<'a, Bytes: ByteSet> {
pub bytes: &'a Bytes,
}
impl<Input: InputIndexer, Dir: Direction, Bytes: ByteSet> SingleCharMatcher<Input, Dir>
for MatchByteSet<'_, Bytes>
{
#[inline(always)]
fn matches(&self, input: &Input, dir: Dir, pos: &mut Input::Position) -> bool {
if Input::CODE_UNITS_ARE_BYTES {
cursor::next_byte(input, dir, pos).is_some_and(|b| self.bytes.contains(b))
} else {
cursor::next(input, dir, pos)
.and_then(|c| c.as_u32().try_into().ok())
.is_some_and(|c| self.bytes.contains(c))
}
}
}
pub struct MatchByteArraySet<ArraySet: SmallArraySet>(pub ByteArraySet<ArraySet>);
impl<Input: InputIndexer, Dir: Direction, ArraySet: SmallArraySet> SingleCharMatcher<Input, Dir>
for MatchByteArraySet<ArraySet>
{
#[inline(always)]
fn matches(&self, input: &Input, dir: Dir, pos: &mut Input::Position) -> bool {
if let Some(b) = cursor::next_byte(input, dir, pos) {
self.0.contains(b)
} else {
false
}
}
}
pub struct MatchByteSeq<'a, const N: usize>(pub &'a [u8; N]);
impl<const N: usize, Input: InputIndexer, Dir: Direction> SingleCharMatcher<Input, Dir>
for MatchByteSeq<'_, N>
{
#[inline(always)]
fn matches(&self, input: &Input, dir: Dir, pos: &mut Input::Position) -> bool {
debug_assert!(N <= 4, "This looks like it could match more than one char");
cursor::try_match_lit(input, dir, pos, self.0)
}
}