use std::fmt;
use std::ops::Range;
#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Span {
pub start: usize,
pub end: usize,
}
impl Span {
#[must_use]
pub const fn new(start: usize, end: usize) -> Self {
assert!(start <= end, "a span cannot end before it starts");
Self { start, end }
}
#[must_use]
pub const fn empty(offset: usize) -> Self {
Self::new(offset, offset)
}
#[must_use]
pub const fn start(self) -> usize {
self.start
}
#[must_use]
pub const fn end(self) -> usize {
self.end
}
#[must_use]
pub const fn len(self) -> usize {
self.end - self.start
}
#[must_use]
pub const fn is_empty(self) -> bool {
self.start == self.end
}
#[must_use]
pub const fn contains(self, offset: usize) -> bool {
self.start <= offset && offset < self.end
}
#[must_use]
pub const fn contains_span(self, other: Self) -> bool {
self.start <= other.start && other.end <= self.end
}
#[must_use]
pub const fn cover(self, other: Self) -> Self {
Self::new(
if self.start < other.start {
self.start
} else {
other.start
},
if self.end > other.end {
self.end
} else {
other.end
},
)
}
#[must_use]
pub const fn range(self) -> Range<usize> {
self.start..self.end
}
#[must_use]
pub fn text(self, source: &str) -> Option<&str> {
source.get(self.range())
}
}
impl From<Range<usize>> for Span {
fn from(range: Range<usize>) -> Self {
Self::new(range.start, range.end)
}
}
impl From<Span> for Range<usize> {
fn from(span: Span) -> Self {
span.range()
}
}
impl fmt::Debug for Span {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(formatter, "{}..{}", self.start, self.end)
}
}
impl fmt::Display for Span {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(self, formatter)
}
}