zebra_test/command/
to_regex.rs

1//! Convenience traits for converting to [`Regex`] and [`RegexSet`].
2
3use std::{collections::HashSet, iter};
4
5use itertools::Itertools;
6use regex::{Error, Regex, RegexBuilder, RegexSet, RegexSetBuilder};
7
8/// A trait for converting a value to a [`Regex`].
9pub trait ToRegex {
10    /// Converts the given value to a [`Regex`].
11    ///
12    /// Returns an [`Error`] if conversion fails.
13    fn to_regex(&self) -> Result<Regex, Error>;
14}
15
16// Identity conversions
17
18impl ToRegex for Regex {
19    fn to_regex(&self) -> Result<Regex, Error> {
20        Ok(self.clone())
21    }
22}
23
24impl ToRegex for &Regex {
25    fn to_regex(&self) -> Result<Regex, Error> {
26        Ok((*self).clone())
27    }
28}
29
30// Builder Conversions
31
32impl ToRegex for RegexBuilder {
33    fn to_regex(&self) -> Result<Regex, Error> {
34        self.build()
35    }
36}
37
38impl ToRegex for &RegexBuilder {
39    fn to_regex(&self) -> Result<Regex, Error> {
40        self.build()
41    }
42}
43
44// String conversions
45
46impl ToRegex for String {
47    fn to_regex(&self) -> Result<Regex, Error> {
48        Regex::new(self)
49    }
50}
51
52impl ToRegex for &String {
53    fn to_regex(&self) -> Result<Regex, Error> {
54        Regex::new(self)
55    }
56}
57
58impl ToRegex for &str {
59    fn to_regex(&self) -> Result<Regex, Error> {
60        Regex::new(self)
61    }
62}
63
64/// A trait for converting a value to a [`RegexSet`].
65pub trait ToRegexSet {
66    /// Converts the given values to a [`RegexSet`].
67    ///
68    /// When converting from a [`Regex`] or [`RegexBuilder`],
69    /// resets match flags and limits to the defaults.
70    /// Use a [`RegexSet`] or [`RegexSetBuilder`] to preserve these settings.
71    ///
72    /// Returns an [`Error`] if any conversion fails.
73    fn to_regex_set(&self) -> Result<RegexSet, Error>;
74}
75
76// Identity conversions
77
78impl ToRegexSet for RegexSet {
79    fn to_regex_set(&self) -> Result<RegexSet, Error> {
80        Ok(self.clone())
81    }
82}
83
84impl ToRegexSet for &RegexSet {
85    fn to_regex_set(&self) -> Result<RegexSet, Error> {
86        Ok((*self).clone())
87    }
88}
89
90// Builder Conversions
91
92impl ToRegexSet for RegexSetBuilder {
93    fn to_regex_set(&self) -> Result<RegexSet, Error> {
94        self.build()
95    }
96}
97
98impl ToRegexSet for &RegexSetBuilder {
99    fn to_regex_set(&self) -> Result<RegexSet, Error> {
100        self.build()
101    }
102}
103
104// Single item conversion
105
106impl<T> ToRegexSet for T
107where
108    T: ToRegex,
109{
110    fn to_regex_set(&self) -> Result<RegexSet, Error> {
111        let regex = self.to_regex()?;
112
113        // This conversion discards flags and limits from Regex and RegexBuilder.
114        let regex = regex.as_str();
115
116        RegexSet::new(iter::once(regex))
117    }
118}
119
120/// A trait for collecting an iterator into a [`RegexSet`].
121pub trait CollectRegexSet {
122    /// Collects the iterator values to a [`RegexSet`].
123    ///
124    /// When converting from a [`Regex`] or [`RegexBuilder`],
125    /// resets match flags and limits to the defaults.
126    ///
127    /// Use a [`RegexSet`] or [`RegexSetBuilder`] to preserve these settings,
128    /// via the `*_regex_set` methods.
129    ///
130    /// Returns an [`Error`] if any conversion fails.
131    fn collect_regex_set(self) -> Result<RegexSet, Error>;
132}
133
134// Multi item conversion
135
136impl<I> CollectRegexSet for I
137where
138    I: IntoIterator,
139    I::Item: ToRegexSet,
140{
141    fn collect_regex_set(self) -> Result<RegexSet, Error> {
142        let regexes: Result<Vec<RegexSet>, Error> = self
143            .into_iter()
144            .map(|item| item.to_regex_set())
145            .try_collect();
146        let regexes = regexes?;
147
148        // This conversion discards flags and limits from Regex and RegexBuilder.
149        let regexes = regexes.iter().flat_map(|regex_set| regex_set.patterns());
150
151        RegexSet::new(regexes)
152    }
153}
154
155/// A trait for getting additional information from a [`RegexSet`].
156pub trait RegexSetExt {
157    /// Returns the regex patterns for the supplied `indexes`.
158    fn patterns_for_indexes(&self, indexes: &HashSet<usize>) -> Vec<String>;
159}
160
161impl RegexSetExt for RegexSet {
162    fn patterns_for_indexes(&self, indexes: &HashSet<usize>) -> Vec<String> {
163        self.patterns()
164            .iter()
165            .enumerate()
166            .filter(|(index, _regex)| indexes.contains(index))
167            .map(|(_index, regex)| regex.to_string())
168            .collect()
169    }
170}