use std::{borrow::Cow, error::Error, ops::Range};
pub trait Diagnostic: Error {
fn code(&self) -> Option<Cow<'_, str>> {
None
}
fn severity(&self) -> Option<Severity> {
None
}
fn help(&self) -> Option<Cow<'_, str>> {
None
}
fn note(&self) -> Option<Cow<'_, str>> {
None
}
fn url(&self) -> Option<Cow<'_, str>> {
None
}
fn source_code(&self) -> Option<&dyn SourceCode> {
None
}
fn labels(&self) -> &[LabeledSpan] {
&[]
}
}
#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd, Default)]
pub enum Severity {
Advice,
Warning,
#[default]
Error,
}
pub trait SourceCode: Send + Sync {
fn data(&self) -> &[u8];
fn name(&self) -> Option<&str> {
None
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct LabeledSpan {
label: Option<String>,
span: SourceSpan,
primary: bool,
}
impl LabeledSpan {
#[must_use]
pub const fn new(label: Option<String>, offset: u32, len: u32) -> Self {
Self { label, span: SourceSpan { offset, length: len }, primary: false }
}
#[must_use]
pub fn new_with_span(label: Option<String>, span: impl Into<SourceSpan>) -> Self {
Self { label, span: span.into(), primary: false }
}
#[must_use]
pub fn new_primary_with_span(label: Option<String>, span: impl Into<SourceSpan>) -> Self {
Self { label, span: span.into(), primary: true }
}
pub fn set_span_offset(&mut self, offset: u32) {
self.span.offset = offset;
}
#[must_use]
pub fn at(span: impl Into<SourceSpan>, label: impl Into<String>) -> Self {
Self::new_with_span(Some(label.into()), span)
}
#[must_use]
pub fn underline(span: impl Into<SourceSpan>) -> Self {
Self::new_with_span(None, span)
}
#[must_use]
pub fn label(&self) -> Option<&str> {
self.label.as_deref()
}
#[must_use]
pub const fn inner(&self) -> &SourceSpan {
&self.span
}
#[must_use]
pub const fn offset(&self) -> u32 {
self.span.offset()
}
#[must_use]
pub const fn len(&self) -> u32 {
self.span.len()
}
#[must_use]
pub const fn is_empty(&self) -> bool {
self.span.is_empty()
}
#[must_use]
pub const fn primary(&self) -> bool {
self.primary
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct SourceSpan {
offset: u32,
length: u32,
}
impl SourceSpan {
#[must_use]
#[expect(clippy::trivially_copy_pass_by_ref, reason = "retained for public API compatibility")]
pub const fn offset(&self) -> u32 {
self.offset
}
#[must_use]
#[expect(clippy::trivially_copy_pass_by_ref, reason = "retained for public API compatibility")]
pub const fn len(&self) -> u32 {
self.length
}
#[must_use]
#[expect(clippy::trivially_copy_pass_by_ref, reason = "retained for public API compatibility")]
pub const fn is_empty(&self) -> bool {
self.length == 0
}
}
impl From<(u32, u32)> for SourceSpan {
fn from((start, len): (u32, u32)) -> Self {
Self { offset: start, length: len }
}
}
impl From<Range<u32>> for SourceSpan {
fn from(range: Range<u32>) -> Self {
let length = u32::try_from(range.len()).unwrap_or(u32::MAX);
Self { offset: range.start, length }
}
}