error_enum_core/
lib.rs

1//! # `error-enum-core`
2//!
3//! A core crate for [`error-enum`](https://crates.io/crates/error-enum) providing
4//! traits and implementations for error enums with rich diagnostics support.
5//!
6//! Please refer to [`error-enum`](https://crates.io/crates/error-enum) and
7//! [`its documentation`](https://docs.rs/error-enum/) for more details.
8
9pub use indexer::{Indexer, LineIndexer};
10pub use span::{SimpleSpan, Span};
11use std::fmt;
12
13mod indexer;
14mod span;
15
16#[cfg(feature = "annotate-snippets")]
17mod annotate_snippets_impl;
18#[cfg(feature = "ariadne")]
19mod ariadne_impl;
20#[cfg(feature = "codespan-reporting")]
21mod codespan_reporting_impl;
22#[cfg(feature = "miette")]
23mod miette_impl;
24
25/// Enum representing the kind of an error.
26#[derive(Clone, Copy, Default)]
27pub enum Kind {
28    /// Error kind.
29    #[default]
30    Error,
31    /// Warning kind.
32    Warn,
33}
34
35impl Kind {
36    /// Get short representation of the [Kind].
37    pub fn short_str(&self) -> &'static str {
38        match self {
39            Kind::Error => "E",
40            Kind::Warn => "W",
41        }
42    }
43}
44
45/// Trait for error enums generated by [`error_type!`] macro and [`ErrorType`] derive macro.
46pub trait ErrorEnum: std::error::Error {
47    /// The span type associated with the error enum.
48    type Span: Span;
49    /// The message type associated with the error enum.
50    type Message: fmt::Display;
51
52    /// Get the kind of the error.
53    fn kind(&self) -> Kind;
54    /// Get the number of the error.
55    fn number(&self) -> &str;
56    /// Get the code of the error.
57    ///
58    /// Normally the code is a combination of kind short string and number,
59    /// like "E0", "W1", etc.
60    fn code(&self) -> &str;
61    /// Get the primary span of the error.
62    fn primary_span(&self) -> Self::Span;
63    /// Get the primary message of the error.
64    fn primary_message(&self) -> Self::Message;
65    /// Get the primary label of the error.
66    fn primary_label(&self) -> Self::Message;
67
68    /// Format the error as an [annotate snippet].
69    ///
70    /// [annotate snippet]: https://docs.rs/annotate-snippets/0.9.1/annotate_snippets/snippet/struct.Snippet.html
71    #[cfg(feature = "annotate-snippets")]
72    fn fmt_as_annotate_snippets(&self) -> Result<String, std::io::Error> {
73        let result = annotate_snippets_impl::fmt_as_annotate_snippets(
74            self,
75            annotate_snippets::display_list::FormatOptions::default(),
76        );
77        Ok(result)
78    }
79    /// Format the error as an [annotate snippet] with [format options].
80    ///
81    /// [annotate snippet]: https://docs.rs/annotate-snippets/0.9.1/annotate_snippets/snippet/struct.Snippet.html
82    /// [format options]: https://docs.rs/annotate-snippets/0.9.1/annotate_snippets/display_list/struct.FormatOptions.html
83    #[cfg(feature = "annotate-snippets")]
84    fn fmt_as_annotate_snippets_with_opts(
85        &self,
86        opts: annotate_snippets::display_list::FormatOptions,
87    ) -> Result<String, std::io::Error> {
88        let result = annotate_snippets_impl::fmt_as_annotate_snippets(self, opts);
89        Ok(result)
90    }
91
92    /// Format the error as an [Ariadne report].
93    ///
94    /// [Ariadne report]: https://docs.rs/ariadne/0.6.0/ariadne/struct.Report.html
95    #[cfg(feature = "ariadne")]
96    fn fmt_as_ariadne_report(&self) -> Result<String, std::io::Error> {
97        ariadne_impl::fmt_as_ariadne_report(
98            self,
99            ariadne::Config::new().with_index_type(ariadne::IndexType::Byte),
100        )
101    }
102    /// Format the error as an [Ariadne report] with [Ariadne config].
103    ///
104    /// [Ariadne report]: https://docs.rs/ariadne/0.6.0/ariadne/struct.Report.html
105    /// [Ariadne config]: https://docs.rs/ariadne/0.6.0/ariadne/struct.Config.html
106    #[cfg(feature = "ariadne")]
107    fn fmt_as_ariadne_report_with(
108        &self,
109        config: ariadne::Config,
110    ) -> Result<String, std::io::Error> {
111        ariadne_impl::fmt_as_ariadne_report(self, config)
112    }
113    /// Format the error as an [Codespan diagnostic].
114    ///
115    /// [Codespan diagnostic]: https://docs.rs/codespan-reporting/0.13.1/codespan_reporting/diagnostic/struct.Diagnostic.html
116    /// [Codespan config]: https://docs.rs/codespan-reporting/0.13.1/codespan_reporting/term/config/struct.Config.html
117    #[cfg(feature = "codespan-reporting")]
118    fn as_codespan_diagnostic(
119        &self,
120    ) -> (
121        codespan_reporting::diagnostic::Diagnostic<usize>,
122        codespan_reporting_impl::Files<Self>,
123    ) {
124        codespan_reporting_impl::to_codespan_diagnostic(self)
125    }
126    /// Format the error as an [Codespan diagnostic] with [Codespan config].
127    ///
128    /// [Codespan diagnostic]: https://docs.rs/codespan-reporting/0.13.1/codespan_reporting/diagnostic/struct.Diagnostic.html
129    /// [Codespan config]: https://docs.rs/codespan-reporting/0.13.1/codespan_reporting/term/config/struct.Config.html
130    #[cfg(feature = "codespan-reporting")]
131    fn fmt_as_codespan_diagnostic_with(
132        &self,
133        config: codespan_reporting::term::Config,
134        styles: Option<&codespan_reporting::term::Styles>,
135    ) -> Result<String, impl std::error::Error> {
136        codespan_reporting_impl::fmt_as_codespan_diagnostic(self, config, styles)
137    }
138
139    /// Convert the error to a [Miette diagnostic].
140    ///
141    /// [Miette diagnostic]: https://docs.rs/miette/7.6.0/miette/trait.Diagnostic.html
142    #[cfg(feature = "miette")]
143    fn as_miette_diagnostic(&self) -> impl miette::Diagnostic + '_
144    where
145        Self::Span: Send + Sync,
146    {
147        miette_impl::Wrapper::new(self)
148    }
149    /// Format the error as a [Miette diagnostic] with a [Miette handler].
150    ///
151    /// [Miette diagnostic]: https://docs.rs/miette/7.6.0/miette/trait.Diagnostic.html
152    /// [Miette Handler]: https://docs.rs/miette/7.6.0/miette/trait.ReportHandler.html
153    #[cfg(feature = "miette")]
154    fn fmt_as_miette_diagnostic_with(&self, handler: &impl miette::ReportHandler) -> String
155    where
156        Self: 'static + Sized,
157        Self::Span: Send + Sync,
158    {
159        miette_impl::Wrapper::new(self).fmt_with(handler)
160    }
161}
162
163impl<T: ErrorEnum + ?Sized> ErrorEnum for &T {
164    type Span = T::Span;
165    type Message = T::Message;
166
167    fn kind(&self) -> Kind {
168        (*self).kind()
169    }
170    fn number(&self) -> &str {
171        (*self).number()
172    }
173    fn code(&self) -> &str {
174        (*self).code()
175    }
176    fn primary_span(&self) -> Self::Span {
177        (*self).primary_span()
178    }
179    fn primary_message(&self) -> Self::Message {
180        (*self).primary_message()
181    }
182    fn primary_label(&self) -> Self::Message {
183        (*self).primary_label()
184    }
185
186    #[cfg(feature = "annotate-snippets")]
187    fn fmt_as_annotate_snippets(&self) -> Result<String, std::io::Error> {
188        (*self).fmt_as_annotate_snippets()
189    }
190    #[cfg(feature = "annotate-snippets")]
191    fn fmt_as_annotate_snippets_with_opts(
192        &self,
193        opts: annotate_snippets::display_list::FormatOptions,
194    ) -> Result<String, std::io::Error> {
195        (*self).fmt_as_annotate_snippets_with_opts(opts)
196    }
197
198    #[cfg(feature = "ariadne")]
199    fn fmt_as_ariadne_report(&self) -> Result<String, std::io::Error> {
200        (*self).fmt_as_ariadne_report()
201    }
202    #[cfg(feature = "ariadne")]
203    fn fmt_as_ariadne_report_with(
204        &self,
205        config: ariadne::Config,
206    ) -> Result<String, std::io::Error> {
207        (*self).fmt_as_ariadne_report_with(config)
208    }
209
210    #[cfg(feature = "miette")]
211    fn as_miette_diagnostic(&self) -> impl miette::Diagnostic + '_
212    where
213        Self::Span: Send + Sync,
214    {
215        (*self).as_miette_diagnostic()
216    }
217}