use crate::Span;
use std::{borrow::Cow, ops::Deref};
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct DiagMsg {
inner: Cow<'static, str>,
}
impl Deref for DiagMsg {
type Target = str;
#[inline]
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl From<&'static str> for DiagMsg {
fn from(value: &'static str) -> Self {
Self { inner: Cow::Borrowed(value) }
}
}
impl From<String> for DiagMsg {
fn from(value: String) -> Self {
Self { inner: Cow::Owned(value) }
}
}
impl From<Cow<'static, str>> for DiagMsg {
fn from(value: Cow<'static, str>) -> Self {
Self { inner: value }
}
}
impl DiagMsg {
#[inline]
pub fn as_str(&self) -> &str {
&self.inner
}
}
#[derive(Clone, Debug)]
pub struct SpanLabel {
pub span: Span,
pub is_primary: bool,
pub label: Option<DiagMsg>,
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct MultiSpan {
primary_spans: Vec<Span>,
span_labels: Vec<(Span, DiagMsg)>,
}
impl MultiSpan {
#[inline]
pub fn new() -> Self {
Self { primary_spans: vec![], span_labels: vec![] }
}
pub fn from_span(primary_span: Span) -> Self {
Self { primary_spans: vec![primary_span], span_labels: vec![] }
}
pub fn from_spans(mut vec: Vec<Span>) -> Self {
vec.sort_unstable();
Self { primary_spans: vec, span_labels: vec![] }
}
pub fn push_span_label(&mut self, span: Span, label: impl Into<DiagMsg>) {
self.span_labels.push((span, label.into()));
}
pub fn primary_span(&self) -> Option<Span> {
self.primary_spans.first().copied()
}
pub fn primary_spans(&self) -> &[Span] {
&self.primary_spans
}
pub fn has_primary_spans(&self) -> bool {
!self.is_dummy()
}
pub fn is_dummy(&self) -> bool {
self.primary_spans.iter().all(|sp| sp.is_dummy())
}
pub fn replace(&mut self, before: Span, after: Span) -> bool {
let mut replacements_occurred = false;
for primary_span in &mut self.primary_spans {
if *primary_span == before {
*primary_span = after;
replacements_occurred = true;
}
}
for span_label in &mut self.span_labels {
if span_label.0 == before {
span_label.0 = after;
replacements_occurred = true;
}
}
replacements_occurred
}
pub fn pop_span_label(&mut self) -> Option<(Span, DiagMsg)> {
self.span_labels.pop()
}
pub fn span_labels(&self) -> Vec<SpanLabel> {
let is_primary = |span| self.primary_spans.contains(&span);
let mut span_labels = self
.span_labels
.iter()
.map(|&(span, ref label)| SpanLabel {
span,
is_primary: is_primary(span),
label: Some(label.clone()),
})
.collect::<Vec<_>>();
for &span in &self.primary_spans {
if !span_labels.iter().any(|sl| sl.span == span) {
span_labels.push(SpanLabel { span, is_primary: true, label: None });
}
}
span_labels
}
pub fn has_span_labels(&self) -> bool {
self.span_labels.iter().any(|(sp, _)| !sp.is_dummy())
}
pub fn clone_ignoring_labels(&self) -> Self {
Self { primary_spans: self.primary_spans.clone(), ..Self::new() }
}
}
impl Default for MultiSpan {
fn default() -> Self {
Self::new()
}
}
impl From<Span> for MultiSpan {
fn from(span: Span) -> Self {
Self::from_span(span)
}
}
impl From<Option<Span>> for MultiSpan {
fn from(span: Option<Span>) -> Self {
if let Some(span) = span { Self::from_span(span) } else { Self::new() }
}
}
impl From<Vec<Span>> for MultiSpan {
fn from(spans: Vec<Span>) -> Self {
Self::from_spans(spans)
}
}