summaryrefslogtreecommitdiffstats
path: root/third_party/rust/bindgen/regex_set.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /third_party/rust/bindgen/regex_set.rs
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/bindgen/regex_set.rs')
-rw-r--r--third_party/rust/bindgen/regex_set.rs204
1 files changed, 204 insertions, 0 deletions
diff --git a/third_party/rust/bindgen/regex_set.rs b/third_party/rust/bindgen/regex_set.rs
new file mode 100644
index 0000000000..b78424aae1
--- /dev/null
+++ b/third_party/rust/bindgen/regex_set.rs
@@ -0,0 +1,204 @@
+//! A type that represents the union of a set of regular expressions.
+#![deny(clippy::missing_docs_in_private_items)]
+
+use regex::RegexSet as RxSet;
+use std::cell::Cell;
+
+/// A dynamic set of regular expressions.
+#[derive(Clone, Debug, Default)]
+pub struct RegexSet {
+ items: Vec<Box<str>>,
+ /// Whether any of the items in the set was ever matched. The length of this
+ /// vector is exactly the length of `items`.
+ matched: Vec<Cell<bool>>,
+ set: Option<RxSet>,
+ /// Whether we should record matching items in the `matched` vector or not.
+ record_matches: bool,
+}
+
+impl RegexSet {
+ /// Create a new RegexSet
+ pub fn new() -> RegexSet {
+ RegexSet::default()
+ }
+
+ /// Is this set empty?
+ pub fn is_empty(&self) -> bool {
+ self.items.is_empty()
+ }
+
+ /// Insert a new regex into this set.
+ pub fn insert<S>(&mut self, string: S)
+ where
+ S: AsRef<str>,
+ {
+ self.items.push(string.as_ref().to_owned().into_boxed_str());
+ self.matched.push(Cell::new(false));
+ self.set = None;
+ }
+
+ /// Returns slice of String from its field 'items'
+ pub fn get_items(&self) -> &[Box<str>] {
+ &self.items
+ }
+
+ /// Returns an iterator over regexes in the set which didn't match any
+ /// strings yet.
+ pub fn unmatched_items(&self) -> impl Iterator<Item = &str> {
+ self.items.iter().enumerate().filter_map(move |(i, item)| {
+ if !self.record_matches || self.matched[i].get() {
+ return None;
+ }
+
+ Some(item.as_ref())
+ })
+ }
+
+ /// Construct a RegexSet from the set of entries we've accumulated.
+ ///
+ /// Must be called before calling `matches()`, or it will always return
+ /// false.
+ #[inline]
+ pub fn build(&mut self, record_matches: bool) {
+ self.build_inner(record_matches, None)
+ }
+
+ #[cfg(all(feature = "__cli", feature = "experimental"))]
+ /// Construct a RegexSet from the set of entries we've accumulated and emit diagnostics if the
+ /// name of the regex set is passed to it.
+ ///
+ /// Must be called before calling `matches()`, or it will always return
+ /// false.
+ #[inline]
+ pub fn build_with_diagnostics(
+ &mut self,
+ record_matches: bool,
+ name: Option<&'static str>,
+ ) {
+ self.build_inner(record_matches, name)
+ }
+
+ #[cfg(all(not(feature = "__cli"), feature = "experimental"))]
+ /// Construct a RegexSet from the set of entries we've accumulated and emit diagnostics if the
+ /// name of the regex set is passed to it.
+ ///
+ /// Must be called before calling `matches()`, or it will always return
+ /// false.
+ #[inline]
+ pub(crate) fn build_with_diagnostics(
+ &mut self,
+ record_matches: bool,
+ name: Option<&'static str>,
+ ) {
+ self.build_inner(record_matches, name)
+ }
+
+ fn build_inner(
+ &mut self,
+ record_matches: bool,
+ _name: Option<&'static str>,
+ ) {
+ let items = self.items.iter().map(|item| format!("^({})$", item));
+ self.record_matches = record_matches;
+ self.set = match RxSet::new(items) {
+ Ok(x) => Some(x),
+ Err(e) => {
+ warn!("Invalid regex in {:?}: {:?}", self.items, e);
+ #[cfg(feature = "experimental")]
+ if let Some(name) = _name {
+ invalid_regex_warning(self, e, name);
+ }
+ None
+ }
+ }
+ }
+
+ /// Does the given `string` match any of the regexes in this set?
+ pub fn matches<S>(&self, string: S) -> bool
+ where
+ S: AsRef<str>,
+ {
+ let s = string.as_ref();
+ let set = match self.set {
+ Some(ref set) => set,
+ None => return false,
+ };
+
+ if !self.record_matches {
+ return set.is_match(s);
+ }
+
+ let matches = set.matches(s);
+ if !matches.matched_any() {
+ return false;
+ }
+ for i in matches.iter() {
+ self.matched[i].set(true);
+ }
+
+ true
+ }
+}
+
+#[cfg(feature = "experimental")]
+fn invalid_regex_warning(
+ set: &RegexSet,
+ err: regex::Error,
+ name: &'static str,
+) {
+ use crate::diagnostics::{Diagnostic, Level, Slice};
+
+ let mut diagnostic = Diagnostic::default();
+
+ match err {
+ regex::Error::Syntax(string) => {
+ if string.starts_with("regex parse error:\n") {
+ let mut source = String::new();
+
+ let mut parsing_source = true;
+
+ for line in string.lines().skip(1) {
+ if parsing_source {
+ if line.starts_with(' ') {
+ source.push_str(line);
+ source.push('\n');
+ continue;
+ }
+ parsing_source = false;
+ }
+ let error = "error: ";
+ if line.starts_with(error) {
+ let (_, msg) = line.split_at(error.len());
+ diagnostic.add_annotation(msg.to_owned(), Level::Error);
+ } else {
+ diagnostic.add_annotation(line.to_owned(), Level::Info);
+ }
+ }
+ let mut slice = Slice::default();
+ slice.with_source(source);
+ diagnostic.add_slice(slice);
+
+ diagnostic.with_title(
+ "Error while parsing a regular expression.",
+ Level::Warn,
+ );
+ } else {
+ diagnostic.with_title(string, Level::Warn);
+ }
+ }
+ err => {
+ let err = err.to_string();
+ diagnostic.with_title(err, Level::Warn);
+ }
+ }
+
+ diagnostic.add_annotation(
+ format!("This regular expression was passed via `{}`.", name),
+ Level::Note,
+ );
+
+ if set.items.iter().any(|item| item.as_ref() == "*") {
+ diagnostic.add_annotation("Wildcard patterns \"*\" are no longer considered valid. Use \".*\" instead.", Level::Help);
+ }
+ diagnostic.display();
+}