#![forbid(unsafe_code)]
#![doc = include_str!("../README.md")]
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct MatchSpan {
pub start: usize,
pub end: usize,
}
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct TextMatch {
pub value: String,
pub span: MatchSpan,
}
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct NamedMatch {
pub name: Option<String>,
pub value: String,
pub span: MatchSpan,
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub enum MatchKind {
Exact,
Prefix,
Suffix,
Contains,
Pattern,
#[default]
Unknown,
}
pub fn is_match_span_valid(input: &str, span: &MatchSpan) -> bool {
span.start <= span.end
&& span.end <= input.len()
&& input.is_char_boundary(span.start)
&& input.is_char_boundary(span.end)
}
pub fn slice_match<'a>(input: &'a str, span: &MatchSpan) -> Option<&'a str> {
if is_match_span_valid(input, span) {
input.get(span.start..span.end)
} else {
None
}
}
pub fn match_len(span: &MatchSpan) -> usize {
span.end.saturating_sub(span.start)
}
pub fn match_is_empty(span: &MatchSpan) -> bool {
match_len(span) == 0
}
pub fn contains_match(matches: &[TextMatch], value: &str) -> bool {
matches.iter().any(|item| item.value == value)
}
pub fn first_match(matches: &[TextMatch]) -> Option<&TextMatch> {
matches.first()
}
pub fn last_match(matches: &[TextMatch]) -> Option<&TextMatch> {
matches.last()
}