chroma_types/regex/
mod.rs

1pub mod hir;
2pub mod literal_expr;
3
4use hir::ChromaHir;
5use regex::Regex;
6use regex_syntax::{hir::Properties, parse};
7use thiserror::Error;
8
9/// Chroma custom wrapper for a Regex pattern.
10///
11/// The `ChromaRegex` struct should represent a regex pattern that is supported by Chroma, and
12/// it could be safely used by further implementations. During construction of this struct we
13/// will perform all necessary validation to check this.
14///
15/// We would like to leverage the regex_syntax crate to provide basic parsing and simplification
16/// of regex expression, and in the process guard against unsupported features by examing the
17/// parsed syntax tree.
18#[derive(Clone, Debug)]
19pub struct ChromaRegex {
20    hir: ChromaHir,
21    pattern: String,
22    properties: Properties,
23}
24
25#[derive(Debug, Error)]
26pub enum ChromaRegexError {
27    #[error("Byte pattern is not allowed")]
28    BytePattern,
29    // NOTE: regex::Error is a large type, so we only store its error message here.
30    #[error("Unexpected regex error: {0}")]
31    Regex(String),
32    // NOTE: regex_syntax::Error is a large type, so we only store its error message here.
33    #[error("Regex syntax errror: {0}")]
34    RegexSyntax(String),
35}
36
37impl ChromaRegex {
38    pub fn hir(&self) -> &ChromaHir {
39        &self.hir
40    }
41    pub fn properties(&self) -> &Properties {
42        &self.properties
43    }
44    pub fn regex(&self) -> Result<Regex, ChromaRegexError> {
45        // NOTE: Although this method return a Result<_, _> type, in practice it should always
46        // be Ok(_) becasue we validate the pattern during struct construction. Specifically,
47        // we verify that the pattern can be properly parsed and is thus a valid pattern supported
48        // by the regex crate.
49        Regex::new(&self.pattern).map_err(|e| ChromaRegexError::Regex(e.to_string()))
50    }
51}
52
53impl TryFrom<String> for ChromaRegex {
54    type Error = ChromaRegexError;
55
56    fn try_from(value: String) -> Result<Self, Self::Error> {
57        let hir = parse(&value).map_err(|e| ChromaRegexError::RegexSyntax(e.to_string()))?;
58        let properties = hir.properties().clone();
59        Ok(Self {
60            hir: hir.try_into()?,
61            pattern: value,
62            properties,
63        })
64    }
65}