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