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