use crate::cursor::{Cursorable, Position};
use crate::folds;
use crate::indexing::ElementType;
use crate::types::{BracketContents, Range};
pub trait CharProperties {
type Element: ElementType;
fn fold(c: Self::Element) -> Self::Element;
fn fold_equals(c1: Self::Element, c2: Self::Element) -> bool {
c1 == c2 || Self::fold(c1) == Self::fold(c2)
}
fn is_word_char(c: Self::Element) -> bool {
match c.as_char() {
'a'..='z' => true,
'A'..='Z' => true,
'0'..='9' => true,
'_' => true,
_ => false,
}
}
fn is_line_terminator(c: Self::Element) -> bool {
let c = c.as_char();
c == '\u{000A}' || c == '\u{000D}' || c == '\u{2028}' || c == '\u{2029}'
}
#[inline(always)]
fn bracket(bc: &BracketContents, c: Self::Element) -> bool {
let cp = c.into();
let contained = bc.cps.intervals().iter().any(|r| r.contains(cp));
contained ^ bc.invert
}
}
pub struct UTF8CharProperties {}
impl CharProperties for UTF8CharProperties {
type Element = char;
fn fold(c: Self::Element) -> Self::Element {
folds::fold(c)
}
}
pub struct ASCIICharProperties {}
impl CharProperties for ASCIICharProperties {
type Element = u8;
fn fold(c: Self::Element) -> Self::Element {
c.to_ascii_lowercase()
}
}
pub fn backref<Cursor: Cursorable>(
orig_range: Range,
position: &mut Position,
cursor: Cursor,
) -> bool {
cursor.subrange_eq(position, orig_range)
}
pub fn backref_icase<Cursor: Cursorable>(
orig_range: Range,
position: &mut Position,
cursor: Cursor,
) -> bool {
let ref_cursor = cursor.subcursor(orig_range.clone());
let mut ref_pos = if Cursor::FORWARD {
Position { pos: 0 }
} else {
Position {
pos: orig_range.end - orig_range.start,
}
};
while let Some(c1) = ref_cursor.next(&mut ref_pos) {
let mut matched = false;
if let Some(c2) = cursor.next(position) {
matched = Cursor::CharProps::fold_equals(c1, c2)
}
if !matched {
return false;
}
}
true
}