Skip to main content

use_match/
lib.rs

1#![forbid(unsafe_code)]
2#![doc = include_str!("../README.md")]
3
4/// A half-open span within a UTF-8 string.
5#[derive(Clone, Debug, Default, PartialEq, Eq)]
6pub struct MatchSpan {
7    pub start: usize,
8    pub end: usize,
9}
10
11/// A matched string value paired with its span.
12#[derive(Clone, Debug, Default, PartialEq, Eq)]
13pub struct TextMatch {
14    pub value: String,
15    pub span: MatchSpan,
16}
17
18/// A matched string value paired with an optional name and span.
19#[derive(Clone, Debug, Default, PartialEq, Eq)]
20pub struct NamedMatch {
21    pub name: Option<String>,
22    pub value: String,
23    pub span: MatchSpan,
24}
25
26/// A conservative classification for how a match was found.
27#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
28pub enum MatchKind {
29    Exact,
30    Prefix,
31    Suffix,
32    Contains,
33    Pattern,
34    #[default]
35    Unknown,
36}
37
38/// Returns `true` when a span is ordered, in bounds, and aligned to character boundaries.
39pub fn is_match_span_valid(input: &str, span: &MatchSpan) -> bool {
40    span.start <= span.end
41        && span.end <= input.len()
42        && input.is_char_boundary(span.start)
43        && input.is_char_boundary(span.end)
44}
45
46/// Returns a borrowed slice for a valid span.
47pub fn slice_match<'a>(input: &'a str, span: &MatchSpan) -> Option<&'a str> {
48    if is_match_span_valid(input, span) {
49        input.get(span.start..span.end)
50    } else {
51        None
52    }
53}
54
55/// Returns the span length using saturating subtraction.
56pub fn match_len(span: &MatchSpan) -> usize {
57    span.end.saturating_sub(span.start)
58}
59
60/// Returns `true` when the span length is zero.
61pub fn match_is_empty(span: &MatchSpan) -> bool {
62    match_len(span) == 0
63}
64
65/// Returns `true` when a match list contains the given value.
66pub fn contains_match(matches: &[TextMatch], value: &str) -> bool {
67    matches.iter().any(|item| item.value == value)
68}
69
70/// Returns the first match in a list.
71pub fn first_match(matches: &[TextMatch]) -> Option<&TextMatch> {
72    matches.first()
73}
74
75/// Returns the last match in a list.
76pub fn last_match(matches: &[TextMatch]) -> Option<&TextMatch> {
77    matches.last()
78}