Repository: microsoft/edit
File: src/icu.rs (Rust)

Code before:
            // and "typically [in] the order of milliseconds", but this claim seems
            // highly outdated. On my CPU from 2021, a limit of 4096 equals roughly 600ms.
            (f.uregex_setTimeLimit)(ptr, 4096, &mut status);
            (f.uregex_setUText)(ptr, text.0 as *const _ as *mut _, &mut status);
            if status.is_failure() {
                return Err(status.as_error());
            }

            Ok(Self(&mut *ptr))
        }
    }

    /// Updates the regex pattern with the given text.
    /// If the text contents have changed, you can pass the same text as you used
    /// initially and it'll trigger ICU to reload the text and invalidate its caches.
    ///
    /// # Safety
    ///
    /// The caller must ensure that the given `Text` outlives the `Regex` instance.
    pub unsafe fn set_text(&mut self, text: &Text) {
        let f = assume_loaded();
        let mut status = icu_ffi::U_ZERO_ERROR;
        unsafe { (f.uregex_setUText)(self.0, text.0 as *const _ as *mut _, &mut status) };
    }

    /// Sets the regex to the absolute offset in the underlying text.
    pub fn reset(&mut self, index: usize) {
        let f = assume_loaded();
        let mut status = icu_ffi::U_ZERO_ERROR;
        unsafe { (f.uregex_reset64)(self.0, index as i64, &mut status) };
    }
}

impl Iterator for Regex {
    type Item = Range<usize>;

    fn next(&mut self) -> Option<Self::Item> {
        let f = assume_loaded();

        let mut status = icu_ffi::U_ZERO_ERROR;
        let ok = unsafe { (f.uregex_findNext)(self.0, &mut status) };
        if !ok {
            return None;
        }

        let start = unsafe { (f.uregex_start64)(self.0, 0, &mut status) };
        let end = unsafe { (f.uregex_end64)(self.0, 0, &mut status) };
        if status.is_failure() {
            return None;
        }


Review comment (bug):
Does setting the offset to the start of the match cause us to deadlock if you Find "a" replace with "a"? Do we need somehow to skip the matched section?

Code after:
            // and "typically [in] the order of milliseconds", but this claim seems
            // highly outdated. On my CPU from 2021, a limit of 4096 equals roughly 600ms.
            (f.uregex_setTimeLimit)(ptr, 4096, &mut status);
            (f.uregex_setUText)(ptr, text.0 as *const _ as *mut _, &mut status);
            if status.is_failure() {
                return Err(status.as_error());
            }

            Ok(Self(&mut *ptr))
        }
    }

    /// Updates the regex pattern with the given text.
    /// If the text contents have changed, you can pass the same text as you used
    /// initially and it'll trigger ICU to reload the text and invalidate its caches.
    ///
    /// # Safety
    ///
    /// The caller must ensure that the given `Text` outlives the `Regex` instance.
    pub unsafe fn set_text(&mut self, text: &Text, offset: usize) {
        let f = assume_loaded();
        let mut status = icu_ffi::U_ZERO_ERROR;
        unsafe { (f.uregex_setUText)(self.0, text.0 as *const _ as *mut _, &mut status) };
        // `uregex_setUText` resets the regex to the start of the text.
        // Because of this, we must also call `uregex_reset64`.
        unsafe { (f.uregex_reset64)(self.0, offset as i64, &mut status) };
    }

    /// Sets the regex to the absolute offset in the underlying text.
    pub fn reset(&mut self, offset: usize) {
        let f = assume_loaded();
        let mut status = icu_ffi::U_ZERO_ERROR;
        unsafe { (f.uregex_reset64)(self.0, offset as i64, &mut status) };
    }
}

impl Iterator for Regex {
    type Item = Range<usize>;

    fn next(&mut self) -> Option<Self::Item> {
        let f = assume_loaded();

        let mut status = icu_ffi::U_ZERO_ERROR;
        let ok = unsafe { (f.uregex_findNext)(self.0, &mut status) };
        if !ok {
            return None;
        }

        let start = unsafe { (f.uregex_start64)(self.0, 0, &mut status) };
        let end = unsafe { (f.uregex_end64)(self.0, 0, &mut status) };
        if status.is_failure() {