1ea88969fSopenharmony_ciuse crate::{Error, Result};
2ea88969fSopenharmony_ciuse proc_macro2::{Ident, Span, TokenStream, TokenTree};
3ea88969fSopenharmony_ci
4ea88969fSopenharmony_cimacro_rules! decl_settings {
5ea88969fSopenharmony_ci    ($($val:expr => $variant:ident),+ $(,)*) => {
6ea88969fSopenharmony_ci        #[derive(PartialEq)]
7ea88969fSopenharmony_ci        pub(crate) enum Setting {
8ea88969fSopenharmony_ci            $($variant),*
9ea88969fSopenharmony_ci        }
10ea88969fSopenharmony_ci
11ea88969fSopenharmony_ci        fn ident_to_setting(ident: Ident) -> Result<Setting> {
12ea88969fSopenharmony_ci            match &*ident.to_string() {
13ea88969fSopenharmony_ci                $($val => Ok(Setting::$variant),)*
14ea88969fSopenharmony_ci                _ => {
15ea88969fSopenharmony_ci                    let possible_vals = [$($val),*]
16ea88969fSopenharmony_ci                        .iter()
17ea88969fSopenharmony_ci                        .map(|v| format!("`{}`", v))
18ea88969fSopenharmony_ci                        .collect::<Vec<_>>()
19ea88969fSopenharmony_ci                        .join(", ");
20ea88969fSopenharmony_ci
21ea88969fSopenharmony_ci                    Err(Error::new(
22ea88969fSopenharmony_ci                        ident.span(),
23ea88969fSopenharmony_ci                        format!("unknown setting `{}`, expected one of {}", ident, possible_vals)))
24ea88969fSopenharmony_ci                }
25ea88969fSopenharmony_ci            }
26ea88969fSopenharmony_ci        }
27ea88969fSopenharmony_ci    };
28ea88969fSopenharmony_ci}
29ea88969fSopenharmony_ci
30ea88969fSopenharmony_cidecl_settings! {
31ea88969fSopenharmony_ci    "assert_unwind_safe" => AssertUnwindSafe,
32ea88969fSopenharmony_ci    "allow_not_macro"    => AllowNotMacro,
33ea88969fSopenharmony_ci    "proc_macro_hack"    => ProcMacroHack,
34ea88969fSopenharmony_ci}
35ea88969fSopenharmony_ci
36ea88969fSopenharmony_cipub(crate) fn parse_settings(input: TokenStream) -> Result<Settings> {
37ea88969fSopenharmony_ci    let mut input = input.into_iter();
38ea88969fSopenharmony_ci    let mut res = Settings(Vec::new());
39ea88969fSopenharmony_ci    loop {
40ea88969fSopenharmony_ci        match input.next() {
41ea88969fSopenharmony_ci            Some(TokenTree::Ident(ident)) => {
42ea88969fSopenharmony_ci                res.0.push(ident_to_setting(ident)?);
43ea88969fSopenharmony_ci            }
44ea88969fSopenharmony_ci            None => return Ok(res),
45ea88969fSopenharmony_ci            other => {
46ea88969fSopenharmony_ci                let span = other.map_or(Span::call_site(), |tt| tt.span());
47ea88969fSopenharmony_ci                return Err(Error::new(span, "expected identifier".to_string()));
48ea88969fSopenharmony_ci            }
49ea88969fSopenharmony_ci        }
50ea88969fSopenharmony_ci
51ea88969fSopenharmony_ci        match input.next() {
52ea88969fSopenharmony_ci            Some(TokenTree::Punct(ref punct)) if punct.as_char() == ',' => {}
53ea88969fSopenharmony_ci            None => return Ok(res),
54ea88969fSopenharmony_ci            other => {
55ea88969fSopenharmony_ci                let span = other.map_or(Span::call_site(), |tt| tt.span());
56ea88969fSopenharmony_ci                return Err(Error::new(span, "expected `,`".to_string()));
57ea88969fSopenharmony_ci            }
58ea88969fSopenharmony_ci        }
59ea88969fSopenharmony_ci    }
60ea88969fSopenharmony_ci}
61ea88969fSopenharmony_ci
62ea88969fSopenharmony_cipub(crate) struct Settings(Vec<Setting>);
63ea88969fSopenharmony_ci
64ea88969fSopenharmony_ciimpl Settings {
65ea88969fSopenharmony_ci    pub(crate) fn is_set(&self, setting: Setting) -> bool {
66ea88969fSopenharmony_ci        self.0.iter().any(|s| *s == setting)
67ea88969fSopenharmony_ci    }
68ea88969fSopenharmony_ci
69ea88969fSopenharmony_ci    pub(crate) fn set(&mut self, setting: Setting) {
70ea88969fSopenharmony_ci        self.0.push(setting)
71ea88969fSopenharmony_ci    }
72ea88969fSopenharmony_ci}
73