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}