use std::{ borrow::Borrow, fmt::{Debug, Formatter}, hash::{Hash, Hasher}, }; #[derive(Copy, Clone, Eq, PartialEq)] pub struct Span { pub lo: usize, pub hi: usize, } impl Debug for Span { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "{}..{}", self.lo, self.hi) } } #[derive(Copy, Clone, Eq)] pub struct Spanned { pub span: Span, pub value: T, } impl Spanned { pub fn as_ref(&self) -> Spanned<&T> { Spanned { span: self.span, value: &self.value, } } pub fn map U>(self, f: F) -> Spanned { Spanned { span: self.span, value: f(self.value), } } pub fn into(self) -> Spanned where T: Into, { Spanned { span: self.span, value: self.value.into(), } } } impl Debug for Spanned { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { self.value.fmt(f)?; write!(f, " @ {:?}", self.span) } } impl PartialEq for Spanned { fn eq(&self, other: &Self) -> bool { self.value.eq(&other.value) } } impl Hash for Spanned { fn hash(&self, state: &mut H) { self.value.hash(state) } } impl Borrow for Spanned { fn borrow(&self) -> &str { &self.value } } pub trait SpannedExt: Sized { fn spanned(self, span: Span) -> Spanned; } impl SpannedExt for T { fn spanned(self, span: Span) -> Spanned { Spanned { span, value: self } } } pub trait DespanExt: Sized { type T; fn despan(self) -> Option; fn despan_into(self) -> Option where Self::T: Into; } impl DespanExt for Option> { type T = T; fn despan(self) -> Option { self.map(|v| v.value) } fn despan_into(self) -> Option where Self::T: Into, { self.map(|v| v.value.into()) } }