use core::fmt;
use core::ops::{Deref, Range};
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub struct DetachedStrSpan {
start: u32,
end: u32,
}
impl DetachedStrSpan {
pub fn as_str<'a>(&self, s: &'a str, offset: usize) -> &'a str {
&s[offset + self.start as usize..offset + self.end as usize]
}
pub fn start(&self) -> u32 {
self.start
}
pub fn end(&self) -> u32 {
self.end
}
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub struct SmallDetachedStrSpan {
pub start: u16,
pub end: u16,
}
impl SmallDetachedStrSpan {
pub fn empty() -> Self {
Self { start: 0, end: 0 }
}
pub fn is_empty(&self) -> bool {
self.start == self.end
}
pub fn as_str<'a>(&self, s: &'a str, offset: usize) -> &'a str {
&s[offset + self.start as usize..offset + self.end as usize]
}
pub fn start(&self) -> u16 {
self.start
}
pub fn end(&self) -> u16 {
self.end
}
}
#[must_use]
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct StrSpan<'a> {
text: &'a str,
start: usize,
}
impl<'a> From<&'a str> for StrSpan<'a> {
#[inline]
fn from(text: &'a str) -> Self {
StrSpan { text, start: 0 }
}
}
impl PartialEq<str> for StrSpan<'_> {
fn eq(&self, other: &str) -> bool {
self.text == other
}
}
impl PartialEq<&str> for StrSpan<'_> {
fn eq(&self, other: &&str) -> bool {
self.text == *other
}
}
impl PartialEq<StrSpan<'_>> for str {
fn eq(&self, other: &StrSpan<'_>) -> bool {
self == other.text
}
}
impl PartialEq<StrSpan<'_>> for &str {
fn eq(&self, other: &StrSpan<'_>) -> bool {
*self == other.text
}
}
impl<'a> StrSpan<'a> {
#[inline]
pub(crate) fn from_substr(text: &str, start: usize, end: usize) -> StrSpan<'_> {
debug_assert!(start <= end);
StrSpan {
text: &text[start..end],
start,
}
}
pub fn is_empty(&self) -> bool {
self.text.is_empty()
}
pub fn detach(&self, offset: usize) -> DetachedStrSpan {
if self.start < offset {
debug_assert!(self.is_empty());
return DetachedStrSpan { start: 0, end: 0 };
}
debug_assert!(self.end() >= self.start);
debug_assert!(self.end() - offset <= u32::MAX as usize);
DetachedStrSpan {
start: (self.start - offset) as u32,
end: (self.end() - offset) as u32,
}
}
pub fn detach_small(&self, offset: usize) -> SmallDetachedStrSpan {
if self.start < offset {
debug_assert!(self.is_empty());
return SmallDetachedStrSpan { start: 0, end: 0 };
}
debug_assert!(self.end() >= self.start);
debug_assert!(self.end() - offset <= u16::MAX as usize);
SmallDetachedStrSpan {
start: (self.start - offset) as u16,
end: (self.end() - offset) as u16,
}
}
#[inline]
pub fn start(&self) -> usize {
self.start
}
#[inline]
pub fn end(&self) -> usize {
self.start + self.text.len()
}
#[inline]
pub fn range(&self) -> Range<usize> {
self.start..self.end()
}
#[inline]
pub fn as_str(&self) -> &'a str {
self.text
}
#[inline]
pub(crate) fn slice_region(&self, start: usize, end: usize) -> StrSpan<'a> {
StrSpan::from_substr(self.text, start, end)
}
}
impl fmt::Debug for StrSpan<'_> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"StrSpan({:?} {}..{})",
self.as_str(),
self.start(),
self.end()
)
}
}
impl fmt::Display for StrSpan<'_> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.as_str())
}
}
impl Deref for StrSpan<'_> {
type Target = str;
fn deref(&self) -> &Self::Target {
self.text
}
}