bon_macros/normalization/cfg/
parse.rs

1use crate::util::prelude::*;
2use syn::parse::{Parse, ParseStream};
3use syn::punctuated::Punctuated;
4
5mod kw {
6    syn::custom_keyword!(__cfgs);
7}
8
9pub(crate) fn parse_predicate_results(tokens: TokenStream) -> Result<Option<PredicateResults>> {
10    let results: WrapOption<PredicateResults> = syn::parse2(tokens)?;
11    Ok(results.0)
12}
13
14// Newtypes over an `Option` to be able to implement trait on it
15#[derive(Debug)]
16struct WrapOption<T>(Option<T>);
17
18/// Represents a special directive inserted at the beginning of the macro parameters
19/// that has the syntax `@cfgs(true, false, true)`. It delivers the results of cfg
20/// evaluations to the macro.
21#[derive(Debug)]
22pub(crate) struct PredicateResults {
23    pub(crate) results: Vec<bool>,
24    pub(crate) recursion_counter: usize,
25    pub(crate) rest: TokenStream,
26}
27
28impl Parse for WrapOption<PredicateResults> {
29    fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
30        if !input.peek(kw::__cfgs) {
31            // We need to exhaust the input stream to avoid a "unexpected token" error
32            input.parse::<TokenStream>()?;
33
34            return Ok(Self(None));
35        }
36
37        input.parse::<kw::__cfgs>()?;
38
39        let results;
40        syn::parenthesized!(results in input);
41
42        let recursion_counter: syn::LitInt = results.parse()?;
43        let recursion_counter = recursion_counter.base10_parse::<usize>()?;
44
45        results.parse::<syn::Token![,]>()?;
46
47        let results: Vec<bool> =
48            Punctuated::<syn::LitBool, syn::Token![,]>::parse_terminated(&results)?
49                .into_iter()
50                .map(|bool| bool.value)
51                .collect();
52
53        let results = PredicateResults {
54            results,
55            recursion_counter,
56            rest: input.parse()?,
57        };
58
59        Ok(Self(Some(results)))
60    }
61}
62
63pub(crate) enum CfgSyntax {
64    Cfg(TokenStream),
65    CfgAttr(CfgAttr),
66}
67
68impl CfgSyntax {
69    pub(crate) fn from_meta(meta: &syn::Meta) -> Result<Option<Self>> {
70        let meta = match meta {
71            syn::Meta::List(meta) => meta,
72            _ => return Ok(None),
73        };
74
75        if meta.path.is_ident("cfg") {
76            return Ok(Some(Self::Cfg(meta.tokens.clone())));
77        }
78
79        if meta.path.is_ident("cfg_attr") {
80            let cfg_attr = syn::parse2(meta.tokens.clone())?;
81            return Ok(Some(Self::CfgAttr(cfg_attr)));
82        }
83
84        Ok(None)
85    }
86}
87
88pub(crate) struct CfgAttr {
89    pub(crate) predicate: syn::Meta,
90    pub(crate) then_branch: Punctuated<syn::Meta, syn::Token![,]>,
91}
92
93impl Parse for CfgAttr {
94    fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
95        let predicate = input.parse()?;
96        input.parse::<syn::Token![,]>()?;
97
98        let then_branch = Punctuated::<syn::Meta, syn::Token![,]>::parse_terminated(input)?;
99
100        Ok(Self {
101            predicate,
102            then_branch,
103        })
104    }
105}