use std::ops::RangeBounds; use proc_macro::{Span, Diagnostic, Literal}; pub type PResult = std::result::Result; pub type DResult = std::result::Result; // An experiment. pub struct Diagnostics(Vec); impl Diagnostics { pub fn new() -> Self { Diagnostics(vec![]) } pub fn push(&mut self, diag: Diagnostic) { self.0.push(diag); } pub fn join(mut self, mut diags: Diagnostics) -> Self { self.0.append(&mut diags.0); self } pub fn emit_head(self) -> Diagnostic { let mut iter = self.0.into_iter(); let mut last = iter.next().expect("Diagnostic::emit_head empty"); for diag in iter { last.emit(); last = diag; } last } pub fn head_err_or(self, ok: T) -> PResult { match self.0.is_empty() { true => Ok(ok), false => Err(self.emit_head()) } } pub fn err_or(self, ok: T) -> DResult { match self.0.is_empty() { true => Ok(ok), false => Err(self) } } } impl From for Diagnostics { fn from(diag: Diagnostic) -> Self { Diagnostics(vec![diag]) } } impl From> for Diagnostics { fn from(diags: Vec) -> Self { Diagnostics(diags) } } use std::ops::Deref; pub struct StringLit(pub String, pub Literal); impl Deref for StringLit { type Target = str; fn deref(&self) -> &str { &self.0 } } impl StringLit { pub fn new>(string: S, span: Span) -> Self { let string = string.into(); let mut lit = Literal::string(&string); lit.set_span(span); StringLit(string, lit) } pub fn span(&self) -> Span { self.1.span() } /// Attempt to obtain a subspan, or, failing that, produce the full span. /// This will create suboptimal diagnostics, but better than failing to build entirely. pub fn subspan>(&self, range: R) -> Span { self.1.subspan(range).unwrap_or_else(|| self.span()) } }