Repository: swc-project/swc
File: crates/swc_common/src/input.rs (Rust)

Code before:
    /// changed in the future.
    ///
    /// # Safety
    /// - start should be less than or equal to end.
    /// - start and end should be in the valid range of input.
    pub unsafe fn slice_to_cur(&mut self, start: BytePos) -> &'a str {
        let end = self.last_pos;

        debug_assert!(start <= end, "Cannot slice {start:?}..{end:?}");
        let s = self.orig;

        let start_idx = (start - self.orig_start).0 as usize;
        let end_idx = (end - self.orig_start).0 as usize;

        debug_assert!(end_idx <= s.len());

        let ret = unsafe { s.get_unchecked(start_idx..end_idx) };

        self.iter = unsafe { s.get_unchecked(end_idx..) }.chars();

        ret
    }

    #[inline]
    pub fn bump_bytes(&mut self, n: usize) {
        let s = self.iter.as_str();
        self.iter = unsafe { s.get_unchecked(n..) }.chars();
        self.last_pos.0 += n as u32;
    }

    pub fn start_pos(&self) -> BytePos {
        self.orig_start
    }

    #[inline(always)]
    pub fn end_pos(&self) -> BytePos {
        self.orig_end
    }
}

/// Creates an [Input] from [SourceFile]. This is an alias for
///
/// ```ignore
///    StringInput::new(&fm.src, fm.start_pos, fm.end_pos)
/// ```
impl<'a> From<&'a SourceFile> for StringInput<'a> {
    fn from(fm: &'a SourceFile) -> Self {
        StringInput::new(&fm.src, fm.start_pos, fm.end_pos)
    }
}


Review comment (suggestion):
Using `get_unchecked` without bounds validation is unsafe. Consider adding a bounds check or documenting the safety invariant that guarantees `n` is always within the string bounds.
```suggestion
        let s = self.iter.as_str();
        assert!(
            n <= s.len(),
            "bump_bytes: n ({}) exceeds remaining string length ({})",
            n,
            s.len()
        );
```

Code after:
    /// changed in the future.
    ///
    /// # Safety
    /// - start should be less than or equal to end.
    /// - start and end should be in the valid range of input.
    pub unsafe fn slice_to_cur(&mut self, start: BytePos) -> &'a str {
        let end = self.last_pos;

        debug_assert!(start <= end, "Cannot slice {start:?}..{end:?}");
        let s = self.orig;

        let start_idx = (start - self.orig_start).0 as usize;
        let end_idx = (end - self.orig_start).0 as usize;

        debug_assert!(end_idx <= s.len());

        let ret = unsafe { s.get_unchecked(start_idx..end_idx) };

        self.iter = unsafe { s.get_unchecked(end_idx..) }.chars();

        ret
    }

    #[inline]
    pub fn bump_bytes(&mut self, n: usize) {
        let s = self.iter.as_str();
        self.iter = unsafe { s.get_unchecked(n..) }.chars();
        self.last_pos.0 += n as u32;
    }

    #[inline]
    pub fn bump_one(&mut self) {
        if self.iter.next().is_some() {
            self.last_pos.0 += 1;
        } else {
            unsafe {
                debug_unreachable!("bump should not be called when cur() == None");
            }
        }
    }

    pub fn start_pos(&self) -> BytePos {
        self.orig_start
    }

    #[inline(always)]
    pub fn end_pos(&self) -> BytePos {
        self.orig_end
    }
}