use std::{fmt::Display, sync::Arc};
use crate::MietteError;
pub trait Diagnostic: std::error::Error {
fn code<'a>(&'a self) -> Box<dyn Display + 'a>;
fn severity(&self) -> Option<Severity> {
None
}
fn help<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
None
}
fn snippets(&self) -> Option<Box<dyn Iterator<Item = DiagnosticSnippet>>> {
None
}
}
impl std::error::Error for Box<dyn Diagnostic> {}
impl<T: Diagnostic + Send + Sync + 'static> From<T>
for Box<dyn Diagnostic + Send + Sync + 'static>
{
fn from(diag: T) -> Self {
Box::new(diag)
}
}
impl<T: Diagnostic + Send + Sync + 'static> From<T> for Box<dyn Diagnostic + Send + 'static> {
fn from(diag: T) -> Self {
Box::<dyn Diagnostic + Send + Sync>::from(diag)
}
}
impl<T: Diagnostic + Send + Sync + 'static> From<T> for Box<dyn Diagnostic + 'static> {
fn from(diag: T) -> Self {
Box::<dyn Diagnostic + Send + Sync>::from(diag)
}
}
pub trait DiagnosticReporter: core::any::Any + Send + Sync {
fn debug(
&self,
diagnostic: &(dyn Diagnostic),
f: &mut core::fmt::Formatter<'_>,
) -> core::fmt::Result;
fn display(
&self,
diagnostic: &(dyn Diagnostic),
f: &mut core::fmt::Formatter<'_>,
) -> core::fmt::Result {
write!(f, "{}", diagnostic)?;
Ok(())
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Severity {
Error,
Warning,
Advice,
}
pub trait Source: std::fmt::Debug + Send + Sync + 'static {
fn read_span<'a>(
&'a self,
span: &SourceSpan,
) -> Result<Box<dyn SpanContents + 'a>, MietteError>;
}
pub trait SpanContents {
fn data(&self) -> &[u8];
fn line(&self) -> usize;
fn column(&self) -> usize;
}
#[derive(Clone, Debug)]
pub struct MietteSpanContents<'a> {
data: &'a [u8],
line: usize,
column: usize,
}
impl<'a> MietteSpanContents<'a> {
pub fn new(data: &'a [u8], line: usize, column: usize) -> MietteSpanContents<'a> {
MietteSpanContents { data, line, column }
}
}
impl<'a> SpanContents for MietteSpanContents<'a> {
fn data(&self) -> &[u8] {
self.data
}
fn line(&self) -> usize {
self.line
}
fn column(&self) -> usize {
self.column
}
}
#[derive(Clone, Debug)]
pub struct DiagnosticSnippet {
pub message: Option<String>,
pub source_name: String,
pub source: Arc<dyn Source>,
pub context: SourceSpan,
pub highlights: Option<Vec<(String, SourceSpan)>>,
}
#[derive(Clone, Debug)]
pub struct SourceSpan {
pub start: SourceOffset,
pub end: SourceOffset,
}
impl SourceSpan {
pub fn new(start: SourceOffset, end: SourceOffset) -> Self {
assert!(
start.offset() <= end.offset(),
"Starting offset must come before the end offset."
);
Self { start, end }
}
pub fn len(&self) -> usize {
self.end.offset() - self.start.offset() + 1
}
pub fn is_empty(&self) -> bool {
self.start.offset() == self.end.offset()
}
}
pub type ByteOffset = usize;
#[derive(Clone, Copy, Debug)]
pub struct SourceOffset(ByteOffset);
impl SourceOffset {
pub fn offset(&self) -> ByteOffset {
self.0
}
}
impl From<ByteOffset> for SourceOffset {
fn from(bytes: ByteOffset) -> Self {
SourceOffset(bytes)
}
}