116 lines
2.9 KiB
Rust
116 lines
2.9 KiB
Rust
use std::{
|
|
fmt,
|
|
ops::{Deref, Range},
|
|
};
|
|
|
|
use eyre::{bail, eyre};
|
|
|
|
#[derive(Clone, Eq, PartialEq)]
|
|
pub struct Span<'a> {
|
|
complete_str: &'a str,
|
|
range: Range<usize>,
|
|
}
|
|
|
|
impl<'a> Span<'a> {
|
|
pub fn new(complete_str: &'a str) -> Self {
|
|
Self {
|
|
complete_str,
|
|
range: 0..complete_str.len(),
|
|
}
|
|
}
|
|
|
|
pub const fn empty() -> Self {
|
|
Span {
|
|
complete_str: "",
|
|
range: 0..0,
|
|
}
|
|
}
|
|
|
|
pub fn get(&self, slice: Range<usize>) -> Option<Self> {
|
|
let start = self.range.start.checked_add(slice.start)?;
|
|
let end = self.range.start.checked_add(slice.end)?;
|
|
|
|
if end > self.range.end || end < start {
|
|
return None;
|
|
}
|
|
|
|
Some(Self {
|
|
complete_str: self.complete_str,
|
|
range: Range { start, end },
|
|
})
|
|
}
|
|
|
|
pub fn complete_str(&self) -> Self {
|
|
Self::new(self.complete_str)
|
|
}
|
|
|
|
pub fn split_at(&self, i: usize) -> Option<(Self, Self)> {
|
|
let head = self.get(0..i)?;
|
|
let tail = self.get(i..self.range.len())?;
|
|
Some((head, tail))
|
|
}
|
|
|
|
pub fn trim_end_matches(&self, p: &str) -> Self {
|
|
if !self.ends_with(p) {
|
|
return self.clone();
|
|
}
|
|
|
|
Self {
|
|
range: self.range.start..self.range.end - p.len(),
|
|
complete_str: self.complete_str,
|
|
}
|
|
}
|
|
|
|
/// Try to merge the spans.
|
|
///
|
|
/// If either spans is empty, this just returns the other one.
|
|
/// This only works if spans are pointing into the same backing buffer, and are adjacent.
|
|
pub fn try_merge(&self, other: &Self) -> eyre::Result<Self> {
|
|
if self.is_empty() {
|
|
return Ok(other.clone());
|
|
}
|
|
|
|
if other.is_empty() {
|
|
return Ok(self.clone());
|
|
}
|
|
|
|
if self.complete_str.as_ptr() != other.complete_str.as_ptr() {
|
|
bail!("Can't merge different strings");
|
|
}
|
|
|
|
if self.range.end == other.range.start {
|
|
Ok(Self {
|
|
range: self.range.start..other.range.end,
|
|
..*self
|
|
})
|
|
} else if self.range.start == other.range.end {
|
|
Ok(Self {
|
|
range: other.range.start..self.range.end,
|
|
..*self
|
|
})
|
|
} else {
|
|
Err(eyre!("String: {:?}", self.complete_str)
|
|
.wrap_err(eyre!("Span 2: {:?}", other.deref()))
|
|
.wrap_err(eyre!("Span 1: {:?}", self.deref()))
|
|
.wrap_err("Can't merge disjoint string spans"))
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Deref for Span<'_> {
|
|
type Target = str;
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
&self.complete_str[self.range.clone()]
|
|
}
|
|
}
|
|
|
|
impl<'a> fmt::Debug for Span<'a> {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
f.debug_tuple("Span")
|
|
.field(&self.range)
|
|
.field(&self.deref())
|
|
.finish()
|
|
}
|
|
}
|