#![no_std]
use core::{cmp::Ordering, ops::Range};
#[cfg(feature = "span-value-usize")]
pub type SpanValue = usize;
#[cfg(feature = "span-value-u128")]
pub type SpanValue = u128;
#[cfg(feature = "span-value-u64")]
pub type SpanValue = u64;
#[cfg(feature = "span-value-u32")]
pub type SpanValue = u32;
#[cfg(feature = "span-value-u16")]
pub type SpanValue = u16;
#[cfg(feature = "span-value-u8")]
pub type SpanValue = u8;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub struct Span {
pub start: SpanValue,
pub end: SpanValue,
}
impl Span {
#[inline(always)]
pub fn new() -> Self {
Self::new_from(0, 0)
}
#[inline(always)]
pub fn new_from(start: SpanValue, end: SpanValue) -> Self {
assert!(end >= start, "cannot create negative-size span");
Span { start, end }
}
#[inline(always)]
pub fn grow_front(&mut self, amount: SpanValue) {
self.end += amount;
}
#[inline(always)]
pub fn with_grow_front(&self, amount: SpanValue) -> Self {
let mut new = *self;
new.end += amount;
new
}
#[inline(always)]
pub fn grow_back(&mut self, amount: SpanValue) {
assert!(
self.start >= amount,
"cannot create a span with a negative start value"
);
self.start -= amount;
}
#[inline(always)]
pub fn with_grow_back(&self, amount: SpanValue) -> Self {
assert!(
self.start >= amount,
"cannot create a span with a negative start value"
);
let mut new = *self;
new.start -= amount;
new
}
#[inline(always)]
pub fn shrink_back(&mut self, amount: SpanValue) {
assert!(self.len() >= amount, "cannot create negative-size span");
self.start += amount;
}
#[inline(always)]
pub fn with_shrink_back(&self, amount: SpanValue) -> Self {
assert!(self.len() >= amount, "cannot create negative-size span");
let mut new = *self;
new.start += amount;
new
}
#[inline(always)]
pub fn shrink_front(&mut self, amount: SpanValue) {
assert!(self.len() >= amount, "cannot create negative-size span");
self.end -= amount;
}
#[inline(always)]
pub fn with_shrink_front(&self, amount: SpanValue) -> Self {
assert!(self.len() >= amount, "cannot create negative-size span");
let mut new = *self;
new.end -= amount;
new
}
#[inline(always)]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
#[inline(always)]
pub fn len(&self) -> SpanValue {
self.end - self.start
}
#[inline(always)]
pub fn reset(&mut self) -> Self {
let span = *self;
self.start = self.end;
span
}
#[allow(clippy::unnecessary_cast)]
pub fn apply<'a>(&self, string: &'a str) -> &'a str {
let mut chars = string.char_indices();
let start = chars
.nth(self.start as usize)
.expect("string is too short to have the span applied")
.0;
let end = chars
.nth(self.len() as usize)
.expect("string is too short to have the span applied")
.0;
&string[start..end]
}
#[allow(clippy::unnecessary_cast)]
pub fn apply_bytes<'a>(&self, string: &'a str) -> &'a str {
assert!(
string.len() >= self.end as usize,
"string is too short to have the span applied"
);
&string[(self.start as usize)..(self.end as usize)]
}
}
impl From<Span> for Range<SpanValue> {
#[inline(always)]
fn from(val: Span) -> Self {
val.start..val.end
}
}
impl From<Range<SpanValue>> for Span {
#[inline(always)]
fn from(value: Range<SpanValue>) -> Self {
Self::new_from(value.start, value.end)
}
}
impl PartialOrd for Span {
#[inline(always)]
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
dual_order(self.start.cmp(&other.start), self.end.cmp(&other.end))
}
}
fn dual_order(x: Ordering, y: Ordering) -> Option<Ordering> {
match (x, y) {
(x, y) if x == y => Some(x),
(Ordering::Greater, Ordering::Less) | (Ordering::Less, Ordering::Greater) => None,
(x, Ordering::Equal) => Some(x),
(Ordering::Equal, x) => Some(x),
_ => unreachable!(),
}
}
#[cfg(feature = "ariadne")]
impl ariadne::Span for Span {
type SourceId = ();
fn source(&self) -> &Self::SourceId {
&()
}
#[allow(clippy::unnecessary_cast)]
fn start(&self) -> usize {
self.start as usize
}
#[allow(clippy::unnecessary_cast)]
fn end(&self) -> usize {
self.end as usize
}
}