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