use crate::{ParseResult, ParseState, StopBecause};
use alloc::{borrow::ToOwned, string::String};
use core::{
ops::Range,
str::pattern::{Pattern, ReverseSearcher, Searcher},
};
pub mod bracket_pair;
#[derive(Copy, Clone, Debug)]
pub struct NamedPattern<P> {
pub pattern: P,
pub message: &'static str,
}
impl<P> Pattern<'static> for NamedPattern<P>
where
P: Pattern<'static>,
{
type Searcher = P::Searcher;
fn into_searcher(self, haystack: &'static str) -> Self::Searcher {
self.pattern.into_searcher(haystack)
}
fn is_contained_in(self, haystack: &'static str) -> bool {
self.pattern.is_contained_in(haystack)
}
fn is_prefix_of(self, haystack: &'static str) -> bool {
self.pattern.is_prefix_of(haystack)
}
fn is_suffix_of(self, haystack: &'static str) -> bool
where
Self::Searcher: ReverseSearcher<'static>,
{
self.pattern.is_suffix_of(haystack)
}
fn strip_prefix_of(self, haystack: &'static str) -> Option<&'static str> {
self.pattern.strip_prefix_of(haystack)
}
fn strip_suffix_of(self, haystack: &'static str) -> Option<&'static str>
where
Self::Searcher: ReverseSearcher<'static>,
{
self.pattern.strip_suffix_of(haystack)
}
}
impl<'p, P> NamedPattern<P>
where
P: Pattern<'p> + Clone,
{
pub fn new(pattern: P, message: &'static str) -> Self {
Self { pattern, message }
}
pub fn consume<'i>(&'p self, input: ParseState<'i>) -> ParseResult<'i, StringView<'i>>
where
'i: 'p,
{
let mut searcher = self.pattern.clone().into_searcher(&input.residual);
match searcher.next_match() {
Some((0, end)) => {
let (state, rest) = input.advance_view(end)?;
state.finish(StringView::new(rest, input.start_offset))
}
_ => StopBecause::missing_string(self.message, input.start_offset)?,
}
}
}
#[derive(Copy, Clone, Debug)]
pub struct StringView<'i> {
start_offset: usize,
string: &'i str,
}
impl<'i> AsRef<str> for StringView<'i> {
fn as_ref(&self) -> &str {
self.string
}
}
impl<'i> StringView<'i> {
pub fn new(string: &'i str, start_offset: usize) -> Self {
Self { start_offset, string }
}
pub fn start_offset(&self) -> usize {
self.start_offset
}
pub fn end_offset(&self) -> usize {
self.start_offset + self.string.len()
}
pub fn as_range(&self) -> Range<usize> {
self.start_offset..self.end_offset()
}
pub fn as_string(&self) -> String {
self.string.to_owned()
}
}