diff --git a/src/dynamic_diagnostic.rs b/src/dynamic_diagnostic.rs new file mode 100644 index 0000000..87055b1 --- /dev/null +++ b/src/dynamic_diagnostic.rs @@ -0,0 +1,72 @@ +use std::{ + error::Error, + fmt::{Debug, Display}, +}; + +use crate::Diagnostic; + +/// Diagnostic that can be created at runtime. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct DynamicDiagnostic { + /// Displayed diagnostic description + pub description: String, + /// Unique diagnostic code to look up more information + /// about this Diagnostic. Ideally also globally unique, and documented + /// in the toplevel crate's documentation for easy searching. + /// Rust path format (`foo::bar::baz`) is recommended, but more classic + /// codes like `E0123` will work just fine. + pub code: Option, +} + +impl Display for DynamicDiagnostic { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", &self.description) + } +} + +impl Error for DynamicDiagnostic {} + +impl Diagnostic for DynamicDiagnostic { + fn code<'a>(&'a self) -> Option> { + self.code + .as_ref() + .map(Box::new) + .map(|c| c as Box) + } +} + +impl DynamicDiagnostic { + /// Create a new dynamic diagnostic with the given description. + /// + /// # Examples + /// ``` + /// use miette::{Diagnostic, DynamicDiagnostic}; + /// + /// let diag = DynamicDiagnostic::new("Oops, something went wrong!"); + /// assert_eq!(diag.to_string(), "Oops, something went wrong!"); + /// assert_eq!(diag.description, "Oops, something went wrong!"); + /// ``` + pub fn new(description: impl Into) -> Self { + Self { + description: description.into(), + code: None, + } + } + + /// Return new diagnostic with the given code. + /// + /// # Examples + /// ``` + /// use miette::{Diagnostic, DynamicDiagnostic}; + /// + /// let diag = DynamicDiagnostic::new("Oops, something went wrong!").with_code("foo::bar::baz"); + /// assert_eq!(diag.description, "Oops, something went wrong!"); + /// assert_eq!(diag.code, Some("foo::bar::baz".to_string())); + /// ``` + pub fn with_code(self, code: impl Into) -> Self { + Self { + code: Some(code.into()), + ..self + } + } +} diff --git a/src/lib.rs b/src/lib.rs index b18239a..c06f25d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -249,7 +249,7 @@ //! To construct your own simple adhoc error use the [miette!] macro: //! ```rust //! // my_app/lib/my_internal_file.rs -//! use miette::{IntoDiagnostic, Result, WrapErr, miette}; +//! use miette::{miette, IntoDiagnostic, Result, WrapErr}; //! use semver::Version; //! //! pub fn some_tool() -> Result { @@ -619,6 +619,7 @@ //! [`ariadne`](https://github.com/zesterer/ariadne), which is MIT licensed. pub use miette_derive::*; +pub use dynamic_diagnostic::*; pub use error::*; pub use eyreish::*; #[cfg(feature = "fancy-no-backtrace")] @@ -631,6 +632,7 @@ pub use protocol::*; mod chain; mod diagnostic_chain; +mod dynamic_diagnostic; mod error; mod eyreish; #[cfg(feature = "fancy-no-backtrace")]