1pub use proc_macro2_diagnostics::Diagnostic;
2pub use proc_macro2_diagnostics::Level;
3pub use proc_macro2_diagnostics::SpanDiagnosticExt;
4
5pub type Result<T> = std::result::Result<T, Diagnostics>;
6
7#[derive(Debug)]
8pub struct Diagnostics(Vec<Diagnostic>);
9
10impl Diagnostics {
11 pub fn new() -> Self {
12 Self(Vec::new())
13 }
14
15 pub fn error(span: proc_macro2::Span, msg: impl Into<String>) -> Self {
16 Self(vec![Diagnostic::spanned(span, Level::Error, msg.into())])
17 }
18
19 pub fn push(&mut self, diag: Diagnostic) {
20 self.0.push(diag);
21 }
22
23 pub fn extend(&mut self, other: Diagnostics) {
24 self.0.extend(other.0);
25 }
26
27 pub fn is_empty(&self) -> bool {
28 self.0.is_empty()
29 }
30
31 pub fn len(&self) -> usize {
32 self.0.len()
33 }
34
35 pub fn has_errors(&self) -> bool {
36 self.0.iter().any(|d| d.level() == Level::Error)
37 }
38
39 pub fn max_level(&self) -> Option<Level> {
40 self.0
41 .iter()
42 .map(|d| d.level())
43 .max_by_key(|l| level_ord(*l))
44 }
45
46 pub fn iter(&self) -> impl Iterator<Item = &Diagnostic> {
47 self.0.iter()
48 }
49
50 pub fn emit(self) -> proc_macro2::TokenStream {
51 let mut tokens = proc_macro2::TokenStream::new();
52
53 for diag in self.0 {
54 tokens.extend(diag.emit_as_item_tokens());
55 }
56
57 tokens
58 }
59}
60
61fn level_ord(level: Level) -> u8 {
62 match level {
63 Level::Note => 0,
64 Level::Help => 1,
65 Level::Warning => 2,
66 Level::Error => 3,
67 _ => 4,
68 }
69}
70
71impl std::fmt::Display for Diagnostics {
72 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
73 for (i, diag) in self.0.iter().enumerate() {
74 if i > 0 {
75 writeln!(f)?;
76 }
77
78 write!(f, "{:?}", diag)?;
79 }
80
81 Ok(())
82 }
83}
84
85impl Default for Diagnostics {
86 fn default() -> Self {
87 Self::new()
88 }
89}
90
91impl From<Diagnostic> for Diagnostics {
92 fn from(diag: Diagnostic) -> Self {
93 Self(vec![diag])
94 }
95}
96
97impl From<syn::Error> for Diagnostics {
98 fn from(error: syn::Error) -> Self {
99 let diags = error
100 .into_iter()
101 .map(|e| Diagnostic::spanned(e.span(), Level::Error, e.to_string()))
102 .collect();
103
104 Self(diags)
105 }
106}
107
108impl IntoIterator for Diagnostics {
109 type Item = Diagnostic;
110 type IntoIter = std::vec::IntoIter<Diagnostic>;
111
112 fn into_iter(self) -> Self::IntoIter {
113 self.0.into_iter()
114 }
115}
116
117impl<'a> IntoIterator for &'a Diagnostics {
118 type Item = &'a Diagnostic;
119 type IntoIter = std::slice::Iter<'a, Diagnostic>;
120
121 fn into_iter(self) -> Self::IntoIter {
122 self.0.iter()
123 }
124}
125
126pub trait ToDiagnostics {
127 fn to_diagnostics(self) -> Diagnostics;
128}
129
130impl ToDiagnostics for syn::Error {
131 fn to_diagnostics(self) -> Diagnostics {
132 Diagnostics::from(self)
133 }
134}
135
136impl ToDiagnostics for Diagnostics {
137 fn to_diagnostics(self) -> Diagnostics {
138 self
139 }
140}