use crate::bytes::MatchBytes;
use crate::Match;
use alloc::string::String;
use core::ops::Range;
pub(crate) fn next_input_pos(text: &[u8], i: usize) -> usize {
let b = match text.get(i) {
None => return i + 1,
Some(&b) => b,
};
i + crate::codepoint_len(b)
}
#[derive(Debug)]
pub struct RegexInput<'h, S: Input + ?Sized> {
haystack: &'h S,
start: usize,
range: Range<usize>,
anchored: bool,
start_text: Option<bool>,
end_text: Option<bool>,
continue_from_previous_match_end: Option<bool>,
}
impl<'h, S: Input + ?Sized> Clone for RegexInput<'h, S> {
fn clone(&self) -> Self {
Self {
haystack: self.haystack,
start: self.start,
range: self.range.clone(),
anchored: self.anchored,
start_text: self.start_text,
end_text: self.end_text,
continue_from_previous_match_end: self.continue_from_previous_match_end,
}
}
}
impl<'h, S: Input + ?Sized> RegexInput<'h, S> {
pub fn new(haystack: &'h S) -> Self {
Self {
haystack,
start: 0,
range: 0..haystack.len(),
anchored: false,
start_text: None,
end_text: None,
continue_from_previous_match_end: None,
}
}
pub fn haystack(&self) -> &'h S {
self.haystack
}
pub fn start(&self) -> usize {
self.start
}
pub fn get_range(&self) -> Range<usize> {
self.range.clone()
}
pub fn from_pos(mut self, start: usize) -> Self {
self.start = start;
self
}
pub fn range(mut self, range: Range<usize>) -> Self {
assert!(range.start <= range.end, "range start must be <= range end");
assert!(
range.end <= self.haystack.len(),
"range end must be within haystack bounds"
);
self.range = range;
self
}
pub fn start_text(mut self, yes: bool) -> Self {
self.start_text = if yes { None } else { Some(false) };
self
}
pub fn end_text(mut self, yes: bool) -> Self {
self.end_text = if yes { None } else { Some(false) };
self
}
pub fn continue_from_previous_match_end(mut self, yes: bool) -> Self {
self.continue_from_previous_match_end = if yes { None } else { Some(false) };
self
}
pub fn anchored(mut self, yes: bool) -> Self {
self.anchored = yes;
self
}
pub(crate) fn effective_start(&self) -> usize {
self.start.max(self.range.start)
}
pub(crate) fn is_done(&self) -> bool {
self.effective_start() > self.range.end
}
pub(crate) fn set_start(&mut self, start: usize) {
self.start = start;
}
pub(crate) fn start_text_override(&self) -> Option<bool> {
self.start_text
}
pub(crate) fn end_text_override(&self) -> Option<bool> {
self.end_text
}
pub(crate) fn continue_from_previous_match_end_override(&self) -> Option<bool> {
self.continue_from_previous_match_end
}
pub(crate) fn is_anchored(&self) -> bool {
self.anchored
}
}
impl<'h, S: Input + ?Sized> From<&'h S> for RegexInput<'h, S> {
fn from(haystack: &'h S) -> Self {
Self::new(haystack)
}
}
pub trait Input {
type Match<'t>
where
Self: 't;
fn len(&self) -> usize;
fn as_bytes(&self) -> &[u8];
fn is_char_boundary(&self, ix: usize) -> bool;
fn is_ascii(&self) -> bool;
fn prev_codepoint_ix(&self, i: usize) -> usize;
fn is_empty(&self) -> bool {
self.len() == 0
}
fn make_match<'t>(&'t self, start: usize, end: usize) -> Self::Match<'t>;
fn advance_position(&self, i: usize) -> usize;
}
impl<S: Input + ?Sized> Input for &S {
type Match<'t>
= S::Match<'t>
where
Self: 't;
fn len(&self) -> usize {
(**self).len()
}
fn as_bytes(&self) -> &[u8] {
(**self).as_bytes()
}
fn is_char_boundary(&self, ix: usize) -> bool {
(**self).is_char_boundary(ix)
}
fn is_ascii(&self) -> bool {
(**self).is_ascii()
}
fn prev_codepoint_ix(&self, i: usize) -> usize {
(**self).prev_codepoint_ix(i)
}
fn make_match<'t>(&'t self, start: usize, end: usize) -> Self::Match<'t> {
(**self).make_match(start, end)
}
fn advance_position(&self, i: usize) -> usize {
(**self).advance_position(i)
}
}
impl Input for str {
type Match<'t> = Match<'t>;
fn len(&self) -> usize {
str::len(self)
}
fn as_bytes(&self) -> &[u8] {
str::as_bytes(self)
}
fn is_char_boundary(&self, ix: usize) -> bool {
str::is_char_boundary(self, ix)
}
fn is_ascii(&self) -> bool {
str::is_ascii(self)
}
fn prev_codepoint_ix(&self, i: usize) -> usize {
crate::prev_codepoint_ix(self, i)
}
fn make_match<'t>(&'t self, start: usize, end: usize) -> Match<'t> {
Match::new(self, start, end)
}
fn advance_position(&self, i: usize) -> usize {
next_input_pos(self.as_bytes(), i)
}
}
impl Input for String {
type Match<'t> = Match<'t>;
fn len(&self) -> usize {
String::len(self)
}
fn as_bytes(&self) -> &[u8] {
String::as_bytes(self)
}
fn is_char_boundary(&self, ix: usize) -> bool {
str::is_char_boundary(self, ix)
}
fn is_ascii(&self) -> bool {
str::is_ascii(self)
}
fn prev_codepoint_ix(&self, i: usize) -> usize {
crate::prev_codepoint_ix(self, i)
}
fn make_match<'t>(&'t self, start: usize, end: usize) -> Match<'t> {
Match::new(self, start, end)
}
fn advance_position(&self, i: usize) -> usize {
next_input_pos(self.as_bytes(), i)
}
}
impl Input for [u8] {
type Match<'t> = MatchBytes<'t>;
fn len(&self) -> usize {
<[u8]>::len(self)
}
fn as_bytes(&self) -> &[u8] {
self
}
fn is_char_boundary(&self, ix: usize) -> bool {
ix == 0 || ix >= <[u8]>::len(self) || self[ix] & 0xC0 != 0x80
}
fn is_ascii(&self) -> bool {
<[u8]>::is_ascii(self)
}
fn prev_codepoint_ix(&self, mut i: usize) -> usize {
i -= 1;
while i > 0 && self[i] & 0xC0 == 0x80 {
i -= 1;
}
i
}
fn make_match<'t>(&'t self, start: usize, end: usize) -> MatchBytes<'t> {
MatchBytes::new(self, start, end)
}
fn advance_position(&self, i: usize) -> usize {
i + 1
}
}
impl<const N: usize> Input for [u8; N] {
type Match<'t> = MatchBytes<'t>;
fn len(&self) -> usize {
N
}
fn as_bytes(&self) -> &[u8] {
self
}
fn is_char_boundary(&self, ix: usize) -> bool {
ix == 0 || ix >= N || self[ix] & 0xC0 != 0x80
}
fn is_ascii(&self) -> bool {
<[u8]>::is_ascii(self)
}
fn prev_codepoint_ix(&self, mut i: usize) -> usize {
i -= 1;
while i > 0 && self[i] & 0xC0 == 0x80 {
i -= 1;
}
i
}
fn make_match<'t>(&'t self, start: usize, end: usize) -> MatchBytes<'t> {
MatchBytes::new(self, start, end)
}
fn advance_position(&self, i: usize) -> usize {
i + 1
}
}