use crate::input::{Bytes, String};
use crate::util::fast;
pub unsafe trait Pattern<I> {
fn find_match(self, input: &I) -> Option<(usize, usize)>;
fn find_reject(self, input: &I) -> Option<usize>;
}
unsafe impl<'i, F> Pattern<Bytes<'i>> for F
where
F: FnMut(u8) -> bool,
{
fn find_match(self, input: &Bytes<'i>) -> Option<(usize, usize)> {
input
.as_dangerous()
.iter()
.copied()
.position(self)
.map(|i| (i, 1))
}
fn find_reject(mut self, input: &Bytes<'i>) -> Option<usize> {
input
.as_dangerous()
.iter()
.copied()
.enumerate()
.find_map(|(i, b)| if (self)(b) { None } else { Some(i) })
}
}
unsafe impl<'i, F> Pattern<String<'i>> for F
where
F: FnMut(char) -> bool,
{
fn find_match(mut self, input: &String<'i>) -> Option<(usize, usize)> {
for (i, c) in input.as_dangerous().char_indices() {
if !(self)(c) {
return Some((i, c.len_utf8()));
}
}
None
}
fn find_reject(mut self, input: &String<'i>) -> Option<usize> {
input.as_dangerous().char_indices().find_map(
|(i, b)| {
if (self)(b) {
None
} else {
Some(i)
}
},
)
}
}
unsafe impl<'i> Pattern<Bytes<'i>> for u8 {
fn find_match(self, input: &Bytes<'i>) -> Option<(usize, usize)> {
fast::find_u8_match(self, input.as_dangerous()).map(|index| (index, 1))
}
fn find_reject(self, input: &Bytes<'i>) -> Option<usize> {
fast::find_u8_reject(self, input.as_dangerous())
}
}
unsafe impl<'i> Pattern<Bytes<'i>> for char {
fn find_match(self, input: &Bytes<'i>) -> Option<(usize, usize)> {
fast::find_char_match(self, input.as_dangerous()).map(|index| (index, self.len_utf8()))
}
fn find_reject(self, input: &Bytes<'i>) -> Option<usize> {
fast::find_char_reject(self, input.as_dangerous())
}
}
unsafe impl<'i> Pattern<String<'i>> for char {
fn find_match(self, input: &String<'i>) -> Option<(usize, usize)> {
fast::find_char_match(self, input.as_dangerous().as_bytes())
.map(|index| (index, self.len_utf8()))
}
fn find_reject(self, input: &String<'i>) -> Option<usize> {
fast::find_char_reject(self, input.as_dangerous().as_bytes())
}
}
unsafe impl<'i> Pattern<Bytes<'i>> for &[u8] {
fn find_match(self, input: &Bytes<'i>) -> Option<(usize, usize)> {
fast::find_slice_match(self, input.as_dangerous()).map(|index| (index, self.len()))
}
fn find_reject(self, input: &Bytes<'i>) -> Option<usize> {
fast::find_slice_reject(self, input.as_dangerous())
}
}
unsafe impl<'i, const N: usize> Pattern<Bytes<'i>> for &[u8; N] {
fn find_match(self, input: &Bytes<'i>) -> Option<(usize, usize)> {
fast::find_slice_match(self, input.as_dangerous()).map(|index| (index, self.len()))
}
fn find_reject(self, input: &Bytes<'i>) -> Option<usize> {
fast::find_slice_reject(self, input.as_dangerous())
}
}
unsafe impl<'i> Pattern<Bytes<'i>> for &str {
fn find_match(self, input: &Bytes<'i>) -> Option<(usize, usize)> {
fast::find_slice_match(self.as_bytes(), input.as_dangerous())
.map(|index| (index, self.len()))
}
fn find_reject(self, input: &Bytes<'i>) -> Option<usize> {
fast::find_slice_reject(self.as_bytes(), input.as_dangerous())
}
}
unsafe impl<'i> Pattern<String<'i>> for &str {
#[inline]
fn find_match(self, input: &String<'i>) -> Option<(usize, usize)> {
fast::find_slice_match(self.as_bytes(), input.as_dangerous().as_bytes())
.map(|index| (index, self.len()))
}
#[inline]
fn find_reject(self, input: &String<'i>) -> Option<usize> {
fast::find_slice_reject(self.as_bytes(), input.as_dangerous().as_bytes())
}
}
#[cfg(feature = "regex")]
unsafe impl<'i> Pattern<String<'i>> for ®ex::Regex {
fn find_match(self, input: &String<'i>) -> Option<(usize, usize)> {
regex::Regex::find(self, input.as_dangerous()).map(|m| (m.start(), m.end() - m.start()))
}
fn find_reject(self, input: &String<'i>) -> Option<usize> {
let mut maybe_reject = 0;
loop {
match regex::Regex::find_at(self, input.as_dangerous(), maybe_reject) {
Some(m) if input.as_dangerous().len() == m.end() => return None,
Some(m) => {
maybe_reject = m.end();
}
None => return Some(maybe_reject),
}
}
}
}
#[cfg(feature = "regex")]
unsafe impl<'i> Pattern<Bytes<'i>> for ®ex::bytes::Regex {
fn find_match(self, input: &Bytes<'i>) -> Option<(usize, usize)> {
regex::bytes::Regex::find(self, input.as_dangerous())
.map(|m| (m.start(), m.end() - m.start()))
}
fn find_reject(self, input: &Bytes<'i>) -> Option<usize> {
let mut maybe_reject = 0;
loop {
match regex::bytes::Regex::find_at(self, input.as_dangerous(), maybe_reject) {
Some(m) if input.len() == m.end() => return None,
Some(m) => {
maybe_reject = m.end();
}
None => return Some(maybe_reject),
}
}
}
}