error_enum_core/
ariadne_impl.rs1use crate::{ErrorType, Kind, Span};
2use alloc::{string::String, vec::Vec};
3use ariadne::{Config, Label, Report, ReportKind};
4use core::{fmt, iter};
5use std::io;
6
7impl From<Kind> for ReportKind<'_> {
8 fn from(kind: Kind) -> Self {
9 match kind {
10 Kind::Error => ReportKind::Error,
11 Kind::Warn => ReportKind::Warning,
12 }
13 }
14}
15
16pub(crate) struct SpanWrapper<T>(T);
17
18impl<T: Span> ariadne::Span for SpanWrapper<T> {
19 type SourceId = T::Uri;
20
21 fn source(&self) -> &Self::SourceId {
22 self.0.uri()
23 }
24 fn start(&self) -> usize {
25 Span::start(&self.0)
26 }
27 fn end(&self) -> usize {
28 Span::end(&self.0)
29 }
30}
31
32type SourceEntry<T> = (
33 <<T as ErrorType>::Span as Span>::Uri,
34 ariadne::Source<<<T as ErrorType>::Span as Span>::Source>,
35);
36
37struct Cache<T: ErrorType + ?Sized> {
38 sources: Vec<SourceEntry<T>>,
39}
40
41impl<T: ErrorType + ?Sized> FromIterator<T::Span> for Cache<T> {
42 fn from_iter<I: IntoIterator<Item = T::Span>>(iter: I) -> Self {
43 let sources = iter
44 .into_iter()
45 .map(
46 |span| -> (
47 <T::Span as Span>::Uri,
48 ariadne::Source<<T::Span as Span>::Source>,
49 ) {
50 (
51 span.uri().clone(),
52 ariadne::Source::from(span.source_text().clone()),
53 )
54 },
55 )
56 .collect();
57 Self { sources }
58 }
59}
60
61impl<T: ErrorType + ?Sized> ariadne::Cache<<T::Span as Span>::Uri> for Cache<T> {
62 type Storage = <T::Span as Span>::Source;
63
64 fn fetch(
65 &mut self,
66 id: &<T::Span as Span>::Uri,
67 ) -> Result<&ariadne::Source<Self::Storage>, impl fmt::Debug> {
68 self.sources
69 .iter()
70 .find(|(uri, _)| uri == id)
71 .map(|(_, source)| source)
72 .ok_or("Source not found")
73 }
74
75 fn display<'a>(&self, id: &'a <T::Span as Span>::Uri) -> Option<impl fmt::Display + 'a> {
76 self.sources
77 .iter()
78 .find(|(uri, _)| uri == id)
79 .map(|(uri, _)| uri)
80 .cloned()
81 }
82}
83
84pub(crate) fn to_ariadne_report<T: ErrorType + ?Sized>(
85 error: &T,
86 buf: &mut impl io::Write,
87 config: Config,
88) -> Result<(), io::Error> {
89 let primary_span = error.primary_span().unwrap_or_default();
90 let primary_message = error.primary_message();
91 let cache: Cache<T> = Cache::from_iter(iter::once(primary_span.clone()));
92 Report::build(error.kind().into(), SpanWrapper(primary_span.clone()))
93 .with_code(error.code())
94 .with_message(primary_message)
95 .with_label(Label::new(SpanWrapper(primary_span)).with_message(error.primary_label()))
96 .with_config(config)
97 .finish()
98 .write(cache, buf)
99}
100pub(crate) fn fmt_as_ariadne_report<T: ErrorType + ?Sized>(
101 error: &T,
102 config: Config,
103) -> Result<String, io::Error> {
104 let mut result = Vec::new();
105 to_ariadne_report(error, &mut result, config)?;
106 String::from_utf8(result).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
107}