use alloc::{boxed::Box, vec::Vec};
pub type Span = core::ops::Range<usize>;
pub trait OptSpanned {
fn opt_span(&self) -> Option<Span>;
fn opt_join_span(&self, other: &impl OptSpanned) -> Option<Span> {
if let Some(l) = self.opt_span() {
Some(l.join_span(other))
} else {
other.opt_span()
}
}
}
pub trait Spanned {
fn span(&self) -> Span;
fn join_span(&self, other: &impl OptSpanned) -> Span {
let l = self.span();
if let Some(r) = other.opt_span() {
usize::min(l.start, r.start)..usize::max(l.end, r.end)
} else {
l
}
}
}
impl<T: Spanned> OptSpanned for T {
fn opt_span(&self) -> Option<Span> {
Some(self.span())
}
}
impl Spanned for Span {
fn span(&self) -> Span {
self.clone()
}
}
impl<T: Spanned> Spanned for Box<T> {
fn span(&self) -> Span {
self.as_ref().span()
}
}
impl<T: OptSpanned> OptSpanned for Option<T> {
fn opt_span(&self) -> Option<Span> {
match &self {
Some(v) => v.opt_span(),
None => None,
}
}
}
impl<T: OptSpanned> OptSpanned for Vec<T> {
fn opt_span(&self) -> Option<Span> {
self.iter().fold(None, |a, b| a.opt_join_span(b))
}
}
impl<T: OptSpanned> OptSpanned for [T] {
fn opt_span(&self) -> Option<Span> {
self.iter().fold(None, |a, b| a.opt_join_span(b))
}
}
impl<S: Spanned> Spanned for (usize, S) {
fn span(&self) -> Span {
self.1.span()
}
}
impl<S: Spanned> Spanned for (usize, usize, S) {
fn span(&self) -> Span {
self.2.span()
}
}
impl<S: Spanned> Spanned for (u32, S) {
fn span(&self) -> Span {
self.1.span()
}
}
impl<S: Spanned> Spanned for (u64, S) {
fn span(&self) -> Span {
self.1.span()
}
}
impl<S: Spanned> Spanned for (f64, S) {
fn span(&self) -> Span {
self.1.span()
}
}
impl<S: Spanned> Spanned for (bool, S) {
fn span(&self) -> Span {
self.1.span()
}
}
impl<'a, S: Spanned> Spanned for (&'a str, S) {
fn span(&self) -> Span {
self.1.span()
}
}
impl<'a, S: Spanned> Spanned for (alloc::borrow::Cow<'a, str>, S) {
fn span(&self) -> Span {
self.1.span()
}
}
impl<S: Spanned, O: OptSpanned> Spanned for (S, O) {
fn span(&self) -> Span {
self.0.join_span(&self.1)
}
}
impl<T1: Spanned, T2: OptSpanned, T3: OptSpanned> Spanned for (T1, T2, T3) {
fn span(&self) -> Span {
self.0.join_span(&self.1).join_span(&self.2)
}
}