tre_regex/
comp.rs

1use std::ffi::c_char;
2use std::mem;
3
4use crate::{
5    err::{regerror, Result},
6    flags::RegcompFlags,
7    tre, Regex,
8};
9
10impl Regex {
11    /// Compiles a regex and wraps it in a `Regex` object.
12    ///
13    /// # Arguments
14    /// * `reg`: regular expression to compile, as a string.
15    /// * `flags`: [`RegcompFlags`] to pass to the function.
16    ///
17    /// # Returns
18    /// An opaque [`Regex`] object will be returned. It will be freed automatically when dropped.
19    ///
20    /// # Errors
21    /// Will return a [`RegexError`] upon failure.
22    ///
23    /// # Examples
24    /// ```
25    /// # use tre_regex::Result;
26    /// # fn main() -> Result<()> {
27    /// use tre_regex::{RegcompFlags, RegexecFlags, Regex};
28    ///
29    /// let regcomp_flags = RegcompFlags::new().add(RegcompFlags::BASIC);
30    /// let regexec_flags = RegexecFlags::new().add(RegexecFlags::NONE);
31    ///
32    /// let compiled_reg = Regex::new("[A-Za-z0-9]*", regcomp_flags)?;
33    /// let matches = compiled_reg.regexec("hello", 1, regexec_flags)?;
34    ///
35    /// for (i, matched) in matches.into_iter().enumerate() {
36    ///     match matched {
37    ///         Some(res) => {
38    ///             match res {
39    ///                 Ok(substr) => println!("Match {i}: '{}'", substr),
40    ///                 Err(e) => println!("Match {i}: <Error: {e}>"),
41    ///             }
42    ///         },
43    ///         None => println!("Match {i}: <None>"),
44    ///     }
45    /// }
46    /// # Ok(())
47    /// # }
48    /// ```
49    ///
50    /// [`RegexError`]: crate::RegexError
51    pub fn new(reg: &str, flags: RegcompFlags) -> Result<Self> {
52        Self::new_bytes(reg.as_bytes(), flags)
53    }
54
55    /// Compiles a regex contained in a `u8` slice and wraps it in a `Regex` object.
56    ///
57    /// # Arguments
58    /// * `reg`: regular expression to compile, as a string.
59    /// * `flags`: [`RegcompFlags`] to pass to the function.
60    ///
61    /// # Returns
62    /// An opaque [`Regex`] object will be returned. It will be freed automatically when dropped.
63    ///
64    /// # Errors
65    /// Will return a [`RegexError`] upon failure.
66    ///
67    /// # Examples
68    /// ```
69    /// # use tre_regex::Result;
70    /// # fn main() -> Result<()> {
71    /// use tre_regex::{RegcompFlags, RegexecFlags, Regex};
72    ///
73    /// let regcomp_flags = RegcompFlags::new().add(RegcompFlags::BASIC);
74    /// let regexec_flags = RegexecFlags::new().add(RegexecFlags::NONE);
75    ///
76    /// let compiled_reg = Regex::new_bytes(b"[A-Za-z0-9]*", regcomp_flags)?;
77    /// let matches = compiled_reg.regexec("hello", 1, regexec_flags)?;
78    ///
79    /// for (i, matched) in matches.into_iter().enumerate() {
80    ///     match matched {
81    ///         Some(res) => {
82    ///             match res {
83    ///                 Ok(substr) => println!("Match {i}: '{}'", substr),
84    ///                 Err(e) => println!("Match {i}: <Error: {e}>"),
85    ///             }
86    ///         },
87    ///         None => println!("Match {i}: <None>"),
88    ///     }
89    /// }
90    /// # Ok(())
91    /// # }
92    /// ```
93    ///
94    /// [`RegexError`]: crate::RegexError
95    pub fn new_bytes(reg: &[u8], flags: RegcompFlags) -> Result<Self> {
96        let mut unwrapped_compiled_reg = mem::MaybeUninit::<tre::regex_t>::uninit();
97
98        // SAFETY: unwrapped_compiled_reg is being initalised. reg is immutably passed and is not
99        // modified by the caller. Wrapping is also impossible.
100        #[allow(clippy::cast_possible_wrap)]
101        let result = unsafe {
102            tre::tre_regncomp(
103                unwrapped_compiled_reg.as_mut_ptr(),
104                reg.as_ptr().cast::<c_char>(),
105                reg.len(),
106                flags.get(),
107            )
108        };
109
110        // SAFETY: tre::tre_regcomp fully initalises compiled_reg
111        let compiled_reg = Self(Some(unsafe { unwrapped_compiled_reg.assume_init() }));
112        if result != 0 {
113            return Err(regerror(&compiled_reg, result));
114        }
115
116        Ok(compiled_reg)
117    }
118}
119
120/// Compiles a regex.
121///
122/// This is a thin wrapper around [`Regex::new`].
123///
124/// # Arguments
125/// * `reg`: regular expression to compile, as a string.
126/// * `flags`: [`RegcompFlags`] to pass to the function.
127///
128/// # Returns
129/// An opaque [`Regex`] object will be returned.
130///
131/// # Errors
132/// Will return a [`RegexError`] upon failure.
133///
134/// # Examples
135/// ```
136/// use tre_regex::{RegcompFlags, RegexecFlags, regcomp, regexec};
137/// # use tre_regex::Result;
138///
139/// # fn main() -> Result<()> {
140/// let regcomp_flags = RegcompFlags::new().add(RegcompFlags::BASIC);
141/// let regexec_flags = RegexecFlags::new().add(RegexecFlags::NONE);
142/// let compiled_reg = regcomp("[A-Za-z0-9]*", regcomp_flags)?;
143/// let matches = regexec(&compiled_reg, "hello", 1, regexec_flags)?;
144/// for (i, matched) in matches.into_iter().enumerate() {
145///     match matched {
146///         Some(substr) => {
147///             match substr {
148///                 Ok(substr) => println!("Match {i}: '{}'", substr),
149///                 Err(e) => println!("Match {i}: <Error: {e}>"),
150///             }
151///         },
152///         None => println!("Match {i}: <None>"),
153///     }
154/// }
155/// # Ok(())
156/// # }
157/// ```
158///
159/// [`RegcompFlags`]: crate::RegcompFlags
160/// [`RegexError`]: crate::RegexError
161#[inline]
162pub fn regcomp(reg: &str, flags: RegcompFlags) -> Result<Regex> {
163    Regex::new(reg, flags)
164}
165
166/// Compiles a regex that is in the form of bytes.
167///
168/// This is a thin wrapper around [`Regex::new_bytes`].
169///
170/// # Arguments
171/// * `reg`: regular expression to compile, as a string.
172/// * `flags`: [`RegcompFlags`] to pass to the function.
173///
174/// # Returns
175/// An opaque [`Regex`] object will be returned.
176///
177/// # Errors
178/// Will return a [`RegexError`] upon failure.
179///
180/// # Examples
181/// ```
182/// use tre_regex::{RegcompFlags, RegexecFlags, regcomp_bytes, regexec_bytes};
183/// # use tre_regex::Result;
184///
185/// # fn main() -> Result<()> {
186/// let regcomp_flags = RegcompFlags::new().add(RegcompFlags::EXTENDED);
187/// let regexec_flags = RegexecFlags::new().add(RegexecFlags::NONE);
188/// let compiled_reg = regcomp_bytes(b"[[:digit:]]*", regcomp_flags)?;
189/// let matches = regexec_bytes(&compiled_reg, b"01234567890", 1, regexec_flags)?;
190/// for (i, matched) in matches.into_iter().enumerate() {
191///     match matched {
192///         Some(substr) => println!("Match {i}: '{}'",
193///             std::str::from_utf8(substr.as_ref()).unwrap()
194///         ),
195///         None => println!("Match {i}: <None>"),
196///     }
197/// }
198/// # Ok(())
199/// # }
200/// ```
201///
202/// [`RegcompFlags`]: crate::RegcompFlags
203/// [`RegexError`]: crate::RegexError
204#[inline]
205pub fn regcomp_bytes(reg: &[u8], flags: RegcompFlags) -> Result<Regex> {
206    Regex::new_bytes(reg, flags)
207}