Skip to main content

ct_regex_internal/haystack/
item.rs

1use std::fmt::Debug;
2
3mod haystack_item {
4    pub trait Sealed {}
5}
6
7use haystack_item::Sealed;
8
9/// A trait that represents an individual item that can be matched against a
10/// [`Regex`](crate::expr::Regex). The primary (and only) two implementors are [`char`] and [`u8`].
11///
12/// # Sealed
13///
14/// This trait is sealed, preventing implementations because the `regex!` macro can't produce
15/// `Regex` types that match against any `HaystackItem` other than the default. If you need to match
16/// against another item type and want to use this crate, you may as well fork it so that you don't
17/// have to write manual `Matcher` expressions.
18pub trait HaystackItem: Debug + Default + Copy + Eq + Ord + Sealed {
19    /// Creates a `Vec` of this item from the provided `&str`, used to convert string literals from
20    /// parsed regular expressions into individual `HaystackItem`s that can be matched in a
21    /// haystack.
22    fn vec_from_str(value: &str) -> Vec<Self>;
23
24    fn is_newline(self) -> bool;
25
26    fn is_return(self) -> bool;
27}
28
29/// A helper for getting the first `char` of a provided `&str`. Returns the width of the character
30/// (possibly zero) and the character itself.
31pub fn first_char_and_width(value: &str) -> (usize, Option<char>) {
32    // Unfortunately, I don't think there is a stable way to get `char`s from a `str` without using
33    // the `chars` or `char_indices` iterators. We can calculate the width easily but may as well
34    // have it done for us.
35    let mut iter = value.char_indices();
36    let first = iter.next();
37    (iter.offset(), first.map(|(_, c)| c))
38}
39
40pub fn first_char(value: &str) -> Option<char> {
41    value.chars().next()
42}
43
44impl Sealed for char {}
45
46impl HaystackItem for char {
47    fn vec_from_str(value: &str) -> Vec<Self> {
48        value.chars().collect()
49    }
50
51    fn is_newline(self) -> bool {
52        self == '\n'
53    }
54
55    fn is_return(self) -> bool {
56        self == '\r'
57    }
58}
59
60impl Sealed for u8 {}
61
62impl HaystackItem for u8 {
63    fn vec_from_str(s: &str) -> Vec<Self> {
64        s.as_bytes().to_vec()
65    }
66
67    fn is_newline(self) -> bool {
68        self == b'\n'
69    }
70
71    fn is_return(self) -> bool {
72        self == b'\r'
73    }
74}