use {
crate::{Arc, Buffer, BufferSource},
::core::{
hash::{Hash, Hasher},
ops::{Add, AddAssign, Bound, Deref, Range, RangeBounds, Sub, SubAssign},
},
::tyfling::{debug, display},
};
#[derive(Clone, Copy, Hash, Eq, PartialEq, Default)]
#[debug("({buf}: {pos})")]
pub struct Loc {
pub pos: u32,
pub(crate) buf: u16,
}
impl Loc {
#[inline]
#[must_use]
pub fn with_len(&self, len: u32) -> Span {
Span::new(*self, *self + len)
}
#[inline]
#[must_use]
pub fn same_buf_as(&self, rhs: &Loc) -> bool {
self.buf == rhs.buf
}
}
impl Add<u32> for Loc {
type Output = Loc;
fn add(mut self, rhs: u32) -> Self::Output {
self += rhs;
self
}
}
impl AddAssign<u32> for Loc {
fn add_assign(&mut self, rhs: u32) {
self.pos += rhs;
}
}
impl Sub<u32> for Loc {
type Output = Loc;
fn sub(mut self, rhs: u32) -> Self::Output {
self -= rhs;
self
}
}
impl SubAssign<u32> for Loc {
fn sub_assign(&mut self, rhs: u32) {
self.pos -= rhs;
}
}
impl Sub<Loc> for Loc {
type Output = u32;
fn sub(self, rhs: Loc) -> Self::Output {
self.pos - rhs.pos
}
}
#[cfg(feature = "miette")]
impl From<Loc> for ::miette::SourceOffset {
fn from(loc: Loc) -> Self {
(loc.pos as usize).into()
}
}
#[derive(Clone, Copy, Hash, Eq, PartialEq, Default)]
#[debug("({buf}: {start}..{end})")]
pub struct Span {
pub(crate) start: u32,
pub(crate) end: u32,
pub(crate) buf: u16,
}
impl Span {
#[inline]
#[must_use]
#[track_caller]
pub fn new(start: Loc, end: Loc) -> Self {
assert_eq!(start.buf, end.buf, "span crosses different bufs");
assert!(start.pos <= end.pos, "backwards span");
Self {
start: start.pos,
end: end.pos,
buf: start.buf,
}
}
#[inline]
#[must_use]
pub fn start(&self) -> Loc {
Loc {
pos: self.start,
buf: self.buf,
}
}
#[inline]
#[must_use]
pub fn end(&self) -> Loc {
Loc {
pos: self.end,
buf: self.buf,
}
}
#[inline]
#[must_use]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
#[inline]
#[must_use]
pub fn len(&self) -> u32 {
self.end - self.start
}
#[inline]
#[must_use]
pub fn contains(&self, loc: &Loc) -> bool {
self.buf == loc.buf && self.start <= loc.pos && loc.pos < self.end
}
#[inline]
#[must_use]
pub fn contains_span(&self, subspan: &Self) -> bool {
self.buf == subspan.buf && self.start <= subspan.start && subspan.end <= self.end
}
#[inline]
#[must_use]
pub fn subspan<B: RangeBounds<u32>>(self, range: B) -> Self {
let span = Self {
start: match range.start_bound() {
Bound::Unbounded => self.start,
Bound::Included(&bound) => self.start + bound,
Bound::Excluded(&bound) => self.start + 1 + bound,
},
end: match range.end_bound() {
Bound::Unbounded => self.end,
Bound::Included(&bound) => self.start + 1 + bound,
Bound::Excluded(&bound) => self.start + bound,
},
buf: self.buf,
};
assert!(span.start <= span.end, "backwards span");
span
}
#[inline]
#[must_use]
#[track_caller]
pub fn union(&self, with: &Self) -> Self {
assert_eq!(self.buf, with.buf, "spans are in different bufs");
Self {
start: ::core::cmp::min(self.start, with.start),
end: ::core::cmp::max(self.end, with.end),
buf: self.buf,
}
}
#[inline]
#[must_use]
#[track_caller]
pub fn intersection(&self, with: &Self) -> Option<Self> {
assert_eq!(self.buf, with.buf, "spans are in different bufs");
let span = Self {
start: ::core::cmp::max(self.start, with.start),
end: ::core::cmp::min(self.end, with.end),
buf: self.buf,
};
(span.start <= span.end).then_some(span)
}
#[inline]
#[must_use]
pub fn with_len(&self, len: u32) -> Self {
Self {
start: self.start,
end: self.start + len,
buf: self.buf,
}
}
#[inline]
#[must_use]
pub fn same_buf_as(&self, loc: Loc) -> bool {
self.buf == loc.buf
}
}
impl From<Loc> for Span {
fn from(loc: Loc) -> Self {
Self::new(loc, loc)
}
}
impl From<Range<Loc>> for Span {
fn from(span: Range<Loc>) -> Self {
Self::new(span.start, span.end)
}
}
#[debug("({buf}+: {start}..{end})", buf = buf.index)]
#[display("{}", &**self)]
pub struct SrcSpan<Src: BufferSource> {
pub(crate) start: u32,
pub(crate) end: u32,
pub(crate) buf: Arc<Buffer<Src>>,
}
impl<Src: BufferSource> SrcSpan<Src> {
#[inline]
#[must_use]
pub fn start(&self) -> Loc {
Loc {
pos: self.start,
buf: self.buf.index,
}
}
#[inline]
#[must_use]
pub fn end(&self) -> Loc {
Loc {
pos: self.end,
buf: self.buf.index,
}
}
#[inline]
#[must_use]
pub fn span(&self) -> Span {
Span {
start: self.start,
end: self.end,
buf: self.buf.index,
}
}
#[inline]
#[must_use]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
#[inline]
#[must_use]
pub fn len(&self) -> u32 {
self.end - self.start
}
#[inline]
#[must_use]
pub fn contains(&self, loc: &Loc) -> bool {
self.buf.index == loc.buf && self.start <= loc.pos && loc.pos < self.end
}
#[inline]
#[must_use]
pub fn contains_span(&self, span: &Span) -> bool {
self.buf.index == span.buf && self.start <= span.start && span.end <= self.end
}
#[inline]
#[must_use]
#[track_caller]
pub fn subspan<B: RangeBounds<u32>>(&self, range: B) -> Self {
let span = Self {
start: match range.start_bound() {
Bound::Unbounded => self.start,
Bound::Included(&bound) => self.start + bound,
Bound::Excluded(&bound) => self.start + 1 + bound,
},
end: match range.end_bound() {
Bound::Unbounded => self.end,
Bound::Included(&bound) => self.start + 1 + bound,
Bound::Excluded(&bound) => self.start + bound,
},
buf: self.buf.clone(),
};
assert!(span.start <= span.end, "backwards span");
span
}
#[inline]
#[must_use]
#[track_caller]
pub fn union(&self, with: &Self) -> Self {
assert_eq!(
self.buf.index, with.buf.index,
"spans are in different bufs"
);
Self {
start: ::core::cmp::min(self.start, with.start),
end: ::core::cmp::max(self.end, with.end),
buf: self.buf.clone(),
}
}
#[inline]
#[must_use]
#[track_caller]
pub fn intersection(&self, with: &Self) -> Option<Self> {
assert_eq!(
self.buf.index, with.buf.index,
"spans are in different bufs"
);
let span = Self {
start: ::core::cmp::max(self.start, with.start),
end: ::core::cmp::min(self.end, with.end),
buf: self.buf.clone(),
};
(span.start <= span.end).then_some(span)
}
#[inline]
#[must_use]
pub fn with_len(&self, len: u32) -> Self {
Self {
start: self.start,
end: self.start + len,
buf: self.buf.clone(),
}
}
#[inline]
#[must_use]
pub fn same_buf_as(&self, loc: Loc) -> bool {
self.buf.index == loc.buf
}
#[inline]
#[must_use]
pub fn buf(&self) -> &Arc<Buffer<Src>> {
&self.buf
}
}
impl<Src: BufferSource> Deref for SrcSpan<Src> {
type Target = str;
fn deref(&self) -> &Self::Target {
&self.buf.src.source()[self.start as usize..self.end as usize]
}
}
impl<Src: BufferSource> Clone for SrcSpan<Src> {
fn clone(&self) -> Self {
Self {
start: self.start,
end: self.end,
buf: Arc::clone(&self.buf),
}
}
}
impl<Src: BufferSource> Hash for SrcSpan<Src> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.start.hash(state);
self.end.hash(state);
self.buf.hash(state);
}
}
impl<Src: BufferSource> PartialEq for SrcSpan<Src> {
fn eq(&self, rhs: &Self) -> bool {
self.start == rhs.start && self.end == rhs.end && self.buf == rhs.buf
}
}
impl<Src: BufferSource> Eq for SrcSpan<Src> {}
impl<Src: BufferSource> From<SrcSpan<Src>> for Span {
fn from(src_span: SrcSpan<Src>) -> Self {
Self {
start: src_span.start,
end: src_span.end,
buf: src_span.buf.index,
}
}
}
#[cfg(feature = "miette")]
impl<Src: BufferSource> From<SrcSpan<Src>> for ::miette::SourceSpan {
fn from(span: SrcSpan<Src>) -> Self {
(span.start as usize..span.end as usize).into()
}
}
#[derive(Clone, Copy, Hash, Eq, PartialEq)]
#[debug("{f0:?} {f1:#?}")]
pub struct Locd<#[debug] T: ?Sized>(pub Loc, pub T);
#[derive(Clone, Copy, Hash, Eq, PartialEq)]
#[debug("{f0:?} {f1:#?}")]
pub struct Spanned<#[debug] T: ?Sized>(pub Span, pub T);
#[derive(Clone, Hash, Eq, PartialEq)]
#[debug("{f0:?} {f1:#?}")]
pub struct SrcSpanned<#[debug] T: ?Sized, Src: BufferSource>(pub SrcSpan<Src>, pub T);
pub trait SpannerExt: Sized {
fn locd(self, loc: Loc) -> Locd<Self> {
Locd(loc, self)
}
fn spanned(self, span: Span) -> Spanned<Self> {
Spanned(span, self)
}
fn src_spanned<Src: BufferSource>(self, src_span: SrcSpan<Src>) -> SrcSpanned<Self, Src> {
SrcSpanned(src_span, self)
}
}
impl<T> SpannerExt for T {}