use crate::value::parse;
use core::ops::Range;
use core::str::FromStr;
use serde::Deserialize;
use serde::Serialize;
#[derive(Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[derive(Serialize, Deserialize)]
pub struct Span(pub(crate) usize, pub(crate) usize);
impl core::fmt::Debug for Span {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "Span({}, {})", self.0, self.1)
}
}
impl core::fmt::Display for Span {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{}-{}", self.0, self.1)
}
}
impl FromStr for Span {
type Err = String;
fn from_str(value: &str) -> Result<Self, Self::Err> {
value
.split_once('-')
.and_then(|(lo, hi)| parse::usize(lo.as_bytes()).map(|lo| (lo, hi)).ok())
.and_then(|(lo, hi)| parse::usize(hi.as_bytes()).map(|hi| (lo, hi)).ok())
.map(|(lo, hi)| Span::new(lo, hi))
.ok_or_else(|| value.to_string())
}
}
impl From<&[u8]> for Span {
fn from(value: &[u8]) -> Self {
Self::new(0, value.len())
}
}
impl From<usize> for Span {
fn from(value: usize) -> Self {
Self::new(0, value)
}
}
impl From<Range<usize>> for Span {
fn from(value: Range<usize>) -> Self {
Self::new(value.start, value.end)
}
}
impl Span {
pub fn new(lo: usize, hi: usize) -> Self {
if lo > hi {
Self::default()
} else {
Self(lo, hi)
}
}
pub fn lo(&self) -> usize {
self.0
}
pub fn hi(&self) -> usize {
self.1
}
pub fn len(&self) -> usize {
self.1.saturating_sub(self.0)
}
pub fn is_empty(&self) -> bool {
self.0 == self.1
}
pub fn with_lo(self, lo: usize) -> Self {
Self(lo, self.1)
}
pub fn with_hi(self, hi: usize) -> Self {
Self(self.0, hi)
}
pub fn into_lo(self) -> Self {
Self(self.0, self.0)
}
pub fn into_hi(self) -> Self {
Self(self.1, self.1)
}
pub fn read<'a, T: Default>(&self, list: &'a [T]) -> &'a [T] {
list.get(self.range()).unwrap_or_default()
}
pub fn range(self) -> Range<usize> {
self.0..self.1
}
pub fn lo_range(self) -> Range<usize> {
self.0..self.0
}
pub fn hi_range(self) -> Range<usize> {
self.1..self.1
}
pub fn contains(self, other: Span) -> bool {
self.0 <= other.0 && self.1 >= other.1
}
#[doc(hidden)]
pub fn diff(self, diff: isize) -> Self {
Span::new(self.0, self.1.saturating_add_signed(diff))
}
#[doc(hidden)]
pub fn expand(self, left: usize, right: usize) -> Self {
Span::new(self.0.saturating_sub(left), self.1.saturating_add(right))
}
#[doc(hidden)]
pub fn contract(self, left: usize, right: usize) -> Self {
Span::new(self.0.saturating_add(left), self.1.saturating_sub(right))
}
#[doc(hidden)]
pub(crate) fn zoom(self, span: Span) -> Self {
Span::new(
self.0.saturating_add(span.lo()),
self.0.saturating_add(span.hi()),
)
}
#[doc(hidden)]
pub fn left(self, span: Span) -> Self {
Span::new(
self.0.saturating_sub(span.lo()),
self.1.saturating_sub(span.lo()),
)
}
#[doc(hidden)]
pub fn right(self, span: Span) -> Self {
Span::new(
self.0.saturating_add(span.lo()),
self.1.saturating_add(span.lo()),
)
}
}