rocket_codegen/
proc_macro_ext.rs

1use std::ops::RangeBounds;
2
3use devise::Diagnostic;
4use proc_macro2::{Span, Literal};
5
6// An experiment.
7pub struct Diagnostics(Vec<Diagnostic>);
8
9impl Diagnostics {
10    pub fn new() -> Self {
11        Diagnostics(vec![])
12    }
13
14    pub fn push(&mut self, diag: Diagnostic) {
15        self.0.push(diag);
16    }
17
18    pub fn emit_head(self) -> Diagnostic {
19        let mut iter = self.0.into_iter();
20        let mut last = iter.next().expect("Diagnostic::emit_head empty");
21        for diag in iter {
22            // FIXME(diag: emit, can there be errors here?)
23            last.emit_as_item_tokens();
24            last = diag;
25        }
26
27        last
28    }
29
30    pub fn head_err_or<T>(self, ok: T) -> devise::Result<T> {
31        match self.0.is_empty() {
32            true => Ok(ok),
33            false => Err(self.emit_head())
34        }
35    }
36}
37
38impl From<Diagnostic> for Diagnostics {
39    fn from(diag: Diagnostic) -> Self {
40        Diagnostics(vec![diag])
41    }
42}
43
44impl From<Vec<Diagnostic>> for Diagnostics {
45    fn from(diags: Vec<Diagnostic>) -> Self {
46        Diagnostics(diags)
47    }
48}
49
50pub struct StringLit(pub String, pub Literal);
51
52impl StringLit {
53    pub fn new<S: Into<String>>(string: S, span: Span) -> Self {
54        let string = string.into();
55        let mut lit = Literal::string(&string);
56        lit.set_span(span);
57        StringLit(string, lit)
58    }
59
60    pub fn span(&self) -> Span {
61        self.1.span()
62    }
63
64    /// Attempt to obtain a subspan, or, failing that, produce the full span.
65    /// This will create suboptimal diagnostics, but better than failing to
66    /// build entirely.
67    pub fn subspan<R: RangeBounds<usize>>(&self, range: R) -> Span {
68        self.1.subspan(range).unwrap_or_else(|| self.span())
69    }
70}
71
72impl syn::parse::Parse for StringLit {
73    fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> {
74        let lit = input.parse::<syn::LitStr>()?;
75        Ok(StringLit::new(lit.value(), lit.span()))
76    }
77}
78
79impl devise::FromMeta for StringLit {
80    fn from_meta(meta: &devise::MetaItem) -> devise::Result<Self> {
81        Ok(StringLit::new(String::from_meta(meta)?, meta.value_span()))
82    }
83}
84
85impl std::ops::Deref for StringLit {
86    type Target = str;
87
88    fn deref(&self) -> &str {
89        &self.0
90    }
91}