1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
use std::mem;

use widestring::WideStr;

use crate::{
    err::{regerror, Result},
    flags::RegcompFlags,
    tre, Regex,
};

impl Regex {
    /// Compiles a regex contained in a [`WideStr`] and wraps it in a `Regex` object.
    ///
    /// # Arguments
    /// * `reg`: regular expression to compile, as a [`WideStr`] .
    /// * `flags`: [`RegcompFlags`] to pass to the function.
    ///
    /// # Returns
    /// An opaque [`Regex`] object will be returned. It will be freed automatically when dropped.
    ///
    /// # Errors
    /// Will return a [`RegexError`] upon failure.
    ///
    /// # Examples
    /// ```
    /// # use tre_regex::Result;
    /// # fn main() -> Result<()> {
    /// use tre_regex::{RegcompFlags, RegexecFlags, Regex};
    /// use widestring::widestr;
    ///
    /// let regcomp_flags = RegcompFlags::new().add(RegcompFlags::BASIC);
    /// let regexec_flags = RegexecFlags::new().add(RegexecFlags::NONE);
    ///
    /// let compiled_reg = Regex::new_wide(widestr!("[A-Za-z0-9]*"), regcomp_flags)?;
    /// let matches = compiled_reg.regwexec(widestr!("hello"), 1, regexec_flags)?;
    ///
    /// for (i, matched) in matches.into_iter().enumerate() {
    ///     match matched {
    ///         Some(substr) => println!("Match {i}: '{}'", substr.display()),
    ///         None => println!("Match {i}: <None>"),
    ///     }
    /// }
    /// # Ok(())
    /// # }
    /// ```
    ///
    /// [`RegexError`]: crate::RegexError
    pub fn new_wide(reg: &WideStr, flags: RegcompFlags) -> Result<Self> {
        let mut unwrapped_compiled_reg = mem::MaybeUninit::<tre::regex_t>::uninit();

        // SAFETY: unwrapped_compiled_reg is being initalised. reg is immutably passed and is not
        // modified by the caller. Wrapping is also impossible.
        #[allow(clippy::cast_possible_wrap)]
        let result = unsafe {
            tre::tre_regwncomp(
                unwrapped_compiled_reg.as_mut_ptr(),
                reg.as_ptr() as *const _,
                reg.len(),
                flags.get(),
            )
        };

        // SAFETY: tre::tre_regcomp fully initalises compiled_reg
        let compiled_reg = Self(Some(unsafe { unwrapped_compiled_reg.assume_init() }));
        if result != 0 {
            return Err(regerror(&compiled_reg, result));
        }

        Ok(compiled_reg)
    }
}

/// Compiles a regex that is in the form of a [`WideStr`].
///
/// This is a thin wrapper around [`Regex::new_wide`].
///
/// # Arguments
/// * `reg`: regular expression to compile, as a [`WideStr`].
/// * `flags`: [`RegcompFlags`] to pass to the function.
///
/// # Returns
/// An opaque [`Regex`] object will be returned.
///
/// # Errors
/// Will return a [`RegexError`] upon failure.
///
/// # Examples
/// ```
/// # use tre_regex::Result;
///
/// # fn main() -> Result<()> {
/// use tre_regex::{RegcompFlags, RegexecFlags, regwcomp, regwexec};
/// use widestring::widestr;
///
/// let regcomp_flags = RegcompFlags::new().add(RegcompFlags::EXTENDED);
/// let regexec_flags = RegexecFlags::new().add(RegexecFlags::NONE);
///
/// let compiled_reg = regwcomp(widestr!("[[:digit:]]*"), regcomp_flags)?;
/// let matches = regwexec(&compiled_reg, widestr!("01234567890"), 1, regexec_flags)?;
///
/// for (i, matched) in matches.into_iter().enumerate() {
///     match matched {
///         Some(substr) => println!("Match {i}: '{}'", substr.display()),
///         None => println!("Match {i}: <None>"),
///     }
/// }
/// # Ok(())
/// # }
/// ```
///
/// [`RegcompFlags`]: crate::RegcompFlags
/// [`RegexError`]: crate::RegexError
#[inline]
pub fn regwcomp(reg: &WideStr, flags: RegcompFlags) -> Result<Regex> {
    Regex::new_wide(reg, flags)
}