use core::{ops::Range, str::Lines};
mod sealed {
pub trait Sealed {}
}
pub trait StrExt: sealed::Sealed {
#[doc(hidden)]
fn not_object_safe(&self) -> (&Self, &Self) {
(self, self)
}
fn line_indices(&self) -> LineIndices<'_>;
}
impl sealed::Sealed for str {}
impl StrExt for str {
#[inline]
fn line_indices(&self) -> LineIndices<'_> {
LineIndices {
start_addr: self as *const str as *const () as usize,
inner: self.lines(),
}
}
}
#[cfg(feature = "alloc")]
impl sealed::Sealed for alloc::string::String {}
#[cfg(feature = "alloc")]
impl StrExt for alloc::string::String {
#[inline]
fn line_indices(&self) -> LineIndices<'_> {
self.as_str().line_indices()
}
}
pub struct LineIndices<'a> {
start_addr: usize,
inner: Lines<'a>,
}
impl<'a> Iterator for LineIndices<'a> {
type Item = (Range<usize>, &'a str);
#[inline]
fn next(&mut self) -> Option<Self::Item> {
let slice = self.inner.next()?;
let offset = (slice as *const str as *const () as usize) - self.start_addr;
Some((offset..offset + slice.len(), slice))
}
}