diff --git a/README.md b/README.md index 59ff88b..42ad9e9 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,6 @@ You can derive a Diagnostic from any `std::error::Error` type. `thiserror` is a great way to define them so, and plays extremely nicely with `miette`! */ -use std::sync::Arc; use miette::Diagnostic; use thiserror::Error; @@ -62,7 +61,7 @@ use thiserror::Error; help("try doing it better next time?"), )] struct MyBad { - src: Arc, + src: String, // Snippets and highlights can be included in the diagnostic! #[snippet(src, "This is the part that broke")] snip: SourceSpan, @@ -101,7 +100,7 @@ fn pretend_this_is_main() -> Result<(), MyBad> { let len = src.len(); Err(MyBad { - src: Arc::new(src), + src, snip: ("bad_file.rs", 0, len).into(), bad_bit: ("this bit here", 9, 3).into(), }) diff --git a/miette-derive/src/snippets.rs b/miette-derive/src/snippets.rs index 5d4e0b0..1d97da7 100644 --- a/miette-derive/src/snippets.rs +++ b/miette-derive/src/snippets.rs @@ -176,12 +176,12 @@ impl Snippets { .map(|msg| match msg { MemberOrString::String(str) => { quote! { - message: std::option::Option::Some(#str.into()), + message: std::option::Option::Some(#str), } } MemberOrString::Member(m) => { quote! { - message: std::option::Option::Some(self.#m.clone()), + message: std::option::Option::Some(self.#m.as_ref()), } } }) @@ -194,21 +194,20 @@ impl Snippets { // Source field let src_ident = &snippet.source; let src_ident = quote! { - // TODO: I don't like this. Think about it more and maybe improve protocol? - source: self.#src_ident.clone(), + source: &self.#src_ident, }; // Context let context = &snippet.snippet; let context = quote! { - context: self.#context.clone(), + context: &self.#context, }; // Highlights let highlights = snippet.highlights.iter().map(|highlight| { let Highlight { highlight } = highlight; quote! { - self.#highlight.clone() + &self.#highlight } }); let highlights = quote! { @@ -229,7 +228,7 @@ impl Snippets { }); Some(quote! { #[allow(unused_variables)] - fn snippets(&self) -> std::option::Option>> { + fn snippets(&self) -> std::option::Option + '_>> { Some(Box::new(vec![ #(#snippets),* ].into_iter())) @@ -248,7 +247,7 @@ impl Snippets { .map(|msg| match msg { MemberOrString::String(str) => { quote! { - message: std::option::Option::Some(#str.into()), + message: std::option::Option::Some(#str), } } MemberOrString::Member(m) => { @@ -259,7 +258,7 @@ impl Snippets { } }; quote! { - message: std::option::Option::Some(#m.clone()), + message: std::option::Option::Some(#m.as_ref()), } } }) @@ -278,7 +277,7 @@ impl Snippets { }; let src_ident = quote! { // TODO: I don't like this. Think about it more and maybe improve protocol? - source: #src_ident.clone(), + source: #src_ident, }; // Context @@ -289,7 +288,7 @@ impl Snippets { } }; let context = quote! { - context: #context.clone(), + context: #context, }; // Highlights @@ -302,7 +301,7 @@ impl Snippets { } }; quote! { - #m.clone() + #m } }); let highlights = quote! { @@ -346,7 +345,7 @@ impl Snippets { }); Some(quote! { #[allow(unused_variables)] - fn snippets(&self) -> std::option::Option>> { + fn snippets(&self) -> std::option::Option + '_>> { match self { #(#variant_arms)* _ => std::option::Option::None, diff --git a/src/protocol.rs b/src/protocol.rs index e1a7ad5..6428a4d 100644 --- a/src/protocol.rs +++ b/src/protocol.rs @@ -4,7 +4,7 @@ that you can implement to get access to miette's (and related library's) full reporting and such features. */ -use std::{fmt::Display, sync::Arc}; +use std::fmt::Display; use crate::MietteError; @@ -36,7 +36,7 @@ pub trait Diagnostic: std::error::Error { /// Additional contextual snippets. This is typically used for adding /// marked-up source file output the way compilers often do. - fn snippets(&self) -> Option>> { + fn snippets(&self) -> Option + '_>> { None } } @@ -171,17 +171,17 @@ impl<'a> SpanContents for MietteSpanContents<'a> { A snippet from a [Source] to be displayed with a message and possibly some highlights. */ #[derive(Clone, Debug)] -pub struct DiagnosticSnippet { +pub struct DiagnosticSnippet<'a> { /// Explanation of this specific diagnostic snippet. - pub message: Option, + pub message: Option<&'a str>, /// A [Source] that can be used to read the actual text of a source. - pub source: Arc, + pub source: &'a (dyn Source), /// The primary [SourceSpan] where this diagnostic is located. - pub context: SourceSpan, + pub context: &'a SourceSpan, /// Additional [SourceSpan]s that mark specific sections of the span, for /// example, to underline specific text within the larger span. They're /// paired with labels that should be applied to those sections. - pub highlights: Option>, + pub highlights: Option>, } /** diff --git a/src/reporter.rs b/src/reporter.rs index 50213ca..f0206cf 100644 --- a/src/reporter.rs +++ b/src/reporter.rs @@ -33,7 +33,7 @@ impl MietteReporter { writeln!(f)?; let context_data = snippet .source - .read_span(&snippet.context) + .read_span(snippet.context) .map_err(|_| fmt::Error)?; let context = std::str::from_utf8(context_data.data()).expect("Bad utf8 detected"); let mut line = context_data.line(); @@ -180,7 +180,8 @@ impl DiagnosticReporter for JokeReporter { "miette, her eyes enormous: you {} miette? you {}? oh! oh! jail for mother! jail for mother for One Thousand Years!!!!", diagnostic.code(), diagnostic.snippets().map(|snippets| { - snippets.map(|snippet| snippet.message).collect::>>() + snippets.map(|snippet| snippet.message.map(|x| x.to_owned())) + .collect::>>() }).flatten().map(|x| x.join(", ")).unwrap_or_else(||"try and cause miette to panic".into()) )?; diff --git a/tests/derive.rs b/tests/derive.rs index b379ef8..b964b13 100644 --- a/tests/derive.rs +++ b/tests/derive.rs @@ -1,5 +1,3 @@ -use std::sync::Arc; - use miette::{Diagnostic, Severity, SourceSpan}; use thiserror::Error; @@ -166,11 +164,9 @@ fn test_snippet_named_struct() { #[diagnostic(code(foo::bar::baz))] struct Foo { // The actual "source code" our contexts will be using. This can be - // reused by multiple contexts! - // - // The `Arc` is so you don't have to clone the entire thing into this - // Diagnostic. We just need to be able to read it~ - src: Arc, + // reused by multiple contexts, and just needs to implement + // miette::Source! + src: String, // The "snippet" span. This is the span that will be displayed to // users. It should be a big enough slice of the Source to provide @@ -215,7 +211,7 @@ fn test_snippet_unnamed_struct() { #[error("welp")] #[diagnostic(code(foo::bar::baz))] struct Foo( - Arc, + String, #[snippet(0, "hi")] SourceSpan, #[highlight(1)] SourceSpan, #[highlight(1)] SourceSpan, @@ -235,7 +231,7 @@ fn test_snippet_enum() { enum Foo { #[diagnostic(code(foo::a))] A { - src: Arc, + src: String, #[snippet(src, "my_snippet.rs", "hi this is where the thing went wrong")] snip: SourceSpan, #[highlight(snip, "var 1")] @@ -249,7 +245,7 @@ fn test_snippet_enum() { }, #[diagnostic(code(foo::b))] B( - Arc, + String, #[snippet(0, "my_snippet.rs", "hi")] SourceSpan, #[highlight(1, "var 1")] SourceSpan, #[highlight(1, "var 2")] SourceSpan, diff --git a/tests/reporter.rs b/tests/reporter.rs index eb4dab7..e8cf333 100644 --- a/tests/reporter.rs +++ b/tests/reporter.rs @@ -1,12 +1,17 @@ -use std::{fmt, sync::Arc}; +use std::fmt; -use miette::{Diagnostic, DiagnosticReporter, DiagnosticSnippet, MietteError, MietteReporter}; +use miette::{ + Diagnostic, DiagnosticReporter, DiagnosticSnippet, MietteError, MietteReporter, SourceSpan, +}; use thiserror::Error; #[derive(Error)] #[error("oops!")] struct MyBad { - snippets: Vec, + message: String, + src: String, + ctx: SourceSpan, + highlight: SourceSpan, } impl fmt::Debug for MyBad { @@ -24,35 +29,28 @@ impl Diagnostic for MyBad { Some(Box::new(&"try doing it better next time?")) } - fn snippets(&self) -> Option>> { - Some(Box::new(self.snippets.clone().into_iter())) + fn snippets(&self) -> Option + '_>> { + Some(Box::new( + vec![DiagnosticSnippet { + message: Some(self.message.as_ref()), + source: &self.src, + context: &self.ctx, + highlights: Some(vec![&self.highlight]), + }] + .into_iter(), + )) } } -#[test] -fn basic() -> Result<(), MietteError> { - let err = MyBad { - snippets: Vec::new(), - }; - let out = format!("{:?}", err); - assert_eq!( - "Error[oops::my::bad]: oops!\n\n﹦try doing it better next time?\n".to_string(), - out - ); - Ok(()) -} - #[test] fn fancy() -> Result<(), MietteError> { let src = "source\n text\n here".to_string(); let len = src.len(); let err = MyBad { - snippets: vec![DiagnosticSnippet { - message: Some("This is the part that broke".into()), - source: Arc::new(src), - highlights: Some(vec![("this bit here", 9, 4).into()]), - context: ("bad_file.rs", 0, len).into(), - }], + message: "This is the part that broke".into(), + src, + ctx: ("bad_file.rs", 0, len).into(), + highlight: ("this bit here", 9, 4).into(), }; let out = format!("{:?}", err); // println!("{}", out);