zng_ext_l10n_proc_macros/
util.rs

1use proc_macro2::{Span, TokenStream};
2use quote::{ToTokens, quote_spanned};
3
4/// Collection of compile errors.
5#[derive(Default)]
6pub struct Errors {
7    tokens: TokenStream,
8}
9impl Errors {
10    /// Push a compile error.
11    pub fn push(&mut self, error: impl ToString, span: Span) {
12        let error = error.to_string();
13        self.tokens.extend(quote_spanned! {span=>
14            compile_error!{#error}
15        })
16    }
17
18    pub fn is_empty(&self) -> bool {
19        self.tokens.is_empty()
20    }
21}
22impl ToTokens for Errors {
23    fn to_tokens(&self, tokens: &mut TokenStream) {
24        tokens.extend(self.tokens.clone())
25    }
26    fn to_token_stream(&self) -> TokenStream {
27        self.tokens.clone()
28    }
29    fn into_token_stream(self) -> TokenStream {
30        self.tokens
31    }
32}
33
34/// Input error not caused by the user.
35macro_rules! non_user_error {
36    ($e:expr) => {
37        panic!("[{}:{}] invalid non-user input: {}", file!(), line!(), $e)
38    };
39    ($fmt:tt, $($args:tt)+) => {
40        non_user_error! {
41            format_args!($fmt, $($args)+)
42        }
43    }
44}
45
46/// `Ident` with custom span.
47macro_rules! ident_spanned {
48    ($span:expr=> $($format_name:tt)+) => {
49        proc_macro2::Ident::new(&format!($($format_name)+), $span)
50    };
51}
52
53macro_rules! non_user_group {
54    ($group_kind:ident, $input:expr) => {
55        {
56            fn inner(input: syn::parse::ParseStream) -> syn::Result<syn::parse::ParseBuffer> {
57                let inner;
58                // this macro inserts a return Err(..) but we want to panic
59                syn::$group_kind!(inner in input);
60                Ok(inner)
61            }
62            inner($input).unwrap_or_else(|e| non_user_error!(e))
63        }
64    };
65    ($group_kind:ident, $input:expr, $ident:expr) => {
66        {
67            let id: syn::Ident = $input.parse().unwrap_or_else(|e| non_user_error!(e));
68            let ident = $ident;
69            if id != ident {
70                non_user_error!(format!("expected `{ident}`"));
71            }
72            non_user_group! { $group_kind, $input }
73        }
74    }
75}
76/// Does a `braced!` parse but panics with [`non_user_error!()`](non_user_error) if the parsing fails.
77macro_rules! non_user_braced {
78    ($input:expr) => {
79        non_user_group! { braced, $input }
80    };
81    ($input:expr, $ident:expr) => {
82        non_user_group! { braced, $input, $ident }
83    };
84}