use super::BytePos;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
pub trait GetSpan {
fn get_span(&self) -> Span;
}
pub trait SetSpan {
fn set_span(&mut self, span: Span);
}
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Span {
pub start: BytePos,
pub end: BytePos,
}
impl Span {
pub fn new(start: usize, end: usize) -> Option<Self> {
if start > end {
None
} else {
Some(Span {
start: BytePos(start),
end: BytePos(end),
})
}
}
pub fn point(pos: usize) -> Self {
Span {
start: BytePos(pos),
end: BytePos(pos),
}
}
pub fn new_unchecked(start: usize, end: usize) -> Self {
Span {
start: BytePos(start),
end: BytePos(end),
}
}
pub const fn empty() -> Self {
Span {
start: BytePos(0),
end: BytePos(0),
}
}
pub fn union(&self, other: &Self) -> Self {
Span {
start: self.start.min(other.start),
end: self.end.max(other.end),
}
}
pub fn maybe_union(&self, other: &Option<Self>) -> Self {
match other {
Some(other) => self.union(other),
None => self.clone(),
}
}
pub fn extend(&self, pos: &BytePos) -> Self {
let mut span = self.clone();
if span.start.0 > pos.0 {
span.start = *pos;
}
if span.end.0 < pos.0 {
span.end = *pos;
}
span
}
pub fn start(&self) -> usize {
self.start.0
}
pub fn end(&self) -> usize {
self.end.0
}
pub fn len(&self) -> usize {
self.end.0 - self.start.0
}
pub fn contains(&self, offset: usize) -> bool {
offset >= self.start.0 && offset < self.end.0
}
pub fn intersects(&self, other: &Self) -> bool {
self.start.0 <= other.end.0 && self.end.0 >= other.start.0
}
}
impl<T> From<WithSpan<T>> for Span {
fn from(with_span: WithSpan<T>) -> Span {
with_span.span
}
}
impl<T> From<&WithSpan<T>> for Span {
fn from(with_span: &WithSpan<T>) -> Span {
with_span.span
}
}
#[derive(Debug, PartialEq, Clone)]
pub struct WithSpan<T> {
pub value: T,
pub span: Span,
}
impl<T> GetSpan for WithSpan<T> {
fn get_span(&self) -> Span {
self.span
}
}
impl<T> SetSpan for WithSpan<T> {
fn set_span(&mut self, span: Span) {
self.span = span;
}
}
impl<T> WithSpan<T> {
pub const fn new(value: T, span: Span) -> Self {
WithSpan { value, span }
}
pub const fn empty(value: T) -> Self {
Self {
value,
span: Span {
start: BytePos(0),
end: BytePos(0),
},
}
}
pub const fn new_unchecked(value: T, start: usize, end: usize) -> Self {
Self {
value,
span: Span {
start: BytePos(start),
end: BytePos(end),
},
}
}
pub const fn as_ref(&self) -> WithSpan<&T> {
WithSpan {
span: self.span,
value: &self.value,
}
}
}