zachs18_stdx/
string.rs

1use core::{ops::Range, str::Lines};
2
3mod sealed {
4    pub trait Sealed {}
5}
6
7pub trait StrExt: sealed::Sealed {
8    #[doc(hidden)]
9    fn __not_object_safe(&self) -> (&Self, &Self) {
10        (self, self)
11    }
12    fn line_indices(&self) -> LineIndices<'_>;
13}
14
15impl sealed::Sealed for str {}
16
17impl StrExt for str {
18    #[inline]
19    fn line_indices(&self) -> LineIndices<'_> {
20        LineIndices {
21            start_addr: self as *const str as *const () as usize,
22            inner: self.lines(),
23        }
24    }
25}
26
27#[cfg(feature = "alloc")]
28impl sealed::Sealed for alloc::string::String {}
29
30#[cfg(feature = "alloc")]
31impl StrExt for alloc::string::String {
32    #[inline]
33    fn line_indices(&self) -> LineIndices<'_> {
34        self.as_str().line_indices()
35    }
36}
37
38pub struct LineIndices<'a> {
39    start_addr: usize,
40    inner: Lines<'a>,
41}
42
43impl<'a> Iterator for LineIndices<'a> {
44    type Item = (Range<usize>, &'a str);
45
46    #[inline]
47    fn next(&mut self) -> Option<Self::Item> {
48        let slice = self.inner.next()?;
49        let offset = (slice as *const str as *const () as usize) - self.start_addr;
50        Some((offset..offset + slice.len(), slice))
51    }
52}