use crate::{BytePos, SessionGlobals};
use std::{
cmp, fmt,
ops::{Deref, DerefMut, Range},
};
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
#[repr(Rust, packed(4))]
pub struct Span {
data: u64,
}
impl Default for Span {
#[inline(always)]
fn default() -> Self {
Self::DUMMY
}
}
impl Default for &Span {
#[inline(always)]
fn default() -> Self {
&Span::DUMMY
}
}
impl fmt::Debug for Span {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fn fallback(span: Span, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Span({lo}..{hi})", lo = span.lo().0, hi = span.hi().0)
}
if SessionGlobals::is_set() {
SessionGlobals::with(|g| {
let sm = &g.source_map;
if !sm.is_empty() {
write!(f, "{}", sm.span_to_diagnostic_string(*self))
} else {
fallback(*self, f)
}
})
} else {
fallback(*self, f)
}
}
}
impl PartialOrd for Span {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Span {
#[inline]
fn cmp(&self, other: &Self) -> cmp::Ordering {
self.lo().cmp(&other.lo()).then(self.hi().cmp(&other.hi()))
}
}
impl Span {
pub const DUMMY: Self = Self::new_(BytePos(0), BytePos(0));
#[inline]
pub fn new(mut lo: BytePos, mut hi: BytePos) -> Self {
if lo > hi {
std::mem::swap(&mut lo, &mut hi);
}
Self::new_(lo, hi)
}
#[inline]
#[cfg_attr(debug_assertions, track_caller)]
pub fn new_unchecked(lo: BytePos, hi: BytePos) -> Self {
debug_assert!(lo <= hi, "creating span with lo {lo:?} > hi {hi:?}");
Self::new_(lo, hi)
}
#[inline(always)]
const fn new_(lo: BytePos, hi: BytePos) -> Self {
Self { data: (lo.0 as u64) | ((hi.0 as u64) << 32) }
}
#[inline]
pub fn to_range(self) -> Range<usize> {
self.lo().to_usize()..self.hi().to_usize()
}
#[inline]
pub fn to_u32_range(self) -> Range<u32> {
self.lo().to_u32()..self.hi().to_u32()
}
#[inline(always)]
pub fn lo(self) -> BytePos {
BytePos(self.data as u32)
}
#[inline]
pub fn with_lo(self, lo: BytePos) -> Self {
Self::new(lo, self.hi())
}
#[inline(always)]
pub fn hi(self) -> BytePos {
BytePos((self.data >> 32) as u32)
}
#[inline]
pub fn with_hi(self, hi: BytePos) -> Self {
Self::new(self.lo(), hi)
}
#[inline]
pub fn shrink_to_lo(self) -> Self {
Self::new(self.lo(), self.lo())
}
#[inline]
pub fn shrink_to_hi(self) -> Self {
Self::new(self.hi(), self.hi())
}
#[inline]
pub fn is_dummy(self) -> bool {
self == Self::DUMMY
}
#[inline]
pub fn contains(self, other: Self) -> bool {
self.lo() <= other.lo() && other.hi() <= self.hi()
}
#[inline]
pub fn overlaps(self, other: Self) -> bool {
self.lo() < other.hi() && other.lo() < self.hi()
}
#[inline]
pub fn is_empty(self, other: Self) -> bool {
self.lo() == other.lo() && self.hi() == other.hi()
}
#[inline]
pub fn split_at(self, pos: u32) -> (Self, Self) {
let len = self.hi().0 - self.lo().0;
debug_assert!(pos <= len);
let split_pos = BytePos(self.lo().0 + pos);
(Self::new(self.lo(), split_pos), Self::new(split_pos, self.hi()))
}
#[inline]
pub fn to(self, end: Self) -> Self {
Self::new(cmp::min(self.lo(), end.lo()), cmp::max(self.hi(), end.hi()))
}
#[inline]
pub fn between(self, end: Self) -> Self {
Self::new(self.hi(), end.lo())
}
#[inline]
pub fn until(self, end: Self) -> Self {
Self::new(self.lo(), end.lo())
}
#[inline]
pub fn join_many(spans: impl IntoIterator<Item = Self>) -> Self {
spans.into_iter().reduce(Self::to).unwrap_or_default()
}
#[inline]
pub fn join_first_last(
spans: impl IntoIterator<Item = Self, IntoIter: DoubleEndedIterator>,
) -> Self {
let mut spans = spans.into_iter();
let first = spans.next().unwrap_or_default();
if let Some(last) = spans.next_back() { first.to(last) } else { first }
}
}
#[derive(Clone, Copy, Debug, Default)]
pub struct Spanned<T> {
pub span: Span,
pub data: T,
}
impl<T> Deref for Spanned<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.data
}
}
impl<T> DerefMut for Spanned<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.data
}
}
impl<T> Spanned<T> {
pub fn map<U, F>(self, f: F) -> Spanned<U>
where
F: FnOnce(T) -> U,
{
Spanned { span: self.span, data: f(self.data) }
}
pub fn as_ref(&self) -> Spanned<&T> {
Spanned { span: self.span, data: &self.data }
}
pub fn as_mut(&mut self) -> Spanned<&mut T> {
Spanned { span: self.span, data: &mut self.data }
}
pub fn into_inner(self) -> T {
self.data
}
}
#[derive(Clone, Copy, Debug)]
pub enum SpannedOption<T> {
Some(T),
None(Span),
}
impl<T> SpannedOption<T> {
pub fn is_none(&self) -> bool {
matches!(&self, Self::None(_))
}
pub fn is_some(&self) -> bool {
matches!(&self, Self::Some(_))
}
pub fn unspan(self) -> Option<T> {
match self {
Self::Some(value) => Some(value),
Self::None(_) => None,
}
}
pub fn map<U, F>(self, f: F) -> SpannedOption<U>
where
F: FnOnce(T) -> U,
{
match self {
Self::Some(value) => SpannedOption::Some(f(value)),
Self::None(span) => SpannedOption::None(span),
}
}
pub fn as_ref(&self) -> SpannedOption<&T> {
match &self {
Self::Some(value) => SpannedOption::Some(value),
Self::None(span) => SpannedOption::None(*span),
}
}
}
impl<T: Deref> SpannedOption<T> {
pub fn as_deref(&self) -> SpannedOption<&<T as Deref>::Target> {
self.as_ref().map(Deref::deref)
}
}
impl<T> From<SpannedOption<T>> for Option<T> {
fn from(spanned: SpannedOption<T>) -> Self {
spanned.unspan()
}
}