cxxbridge_macro/
cfg.rs

1use crate::syntax::cfg::{CfgExpr, ComputedCfg};
2use proc_macro2::{Delimiter, Group, Ident, Span, TokenStream};
3use quote::{ToTokens, TokenStreamExt as _};
4use syn::{token, AttrStyle, Attribute, MacroDelimiter, Meta, MetaList, Path, Token};
5
6impl<'a> ComputedCfg<'a> {
7    pub(crate) fn into_attr(&self) -> Option<Attribute> {
8        if let ComputedCfg::Leaf(CfgExpr::Unconditional) = self {
9            None
10        } else {
11            let span = Span::call_site();
12            Some(Attribute {
13                pound_token: Token![#](span),
14                style: AttrStyle::Outer,
15                bracket_token: token::Bracket(span),
16                meta: Meta::List(MetaList {
17                    path: Path::from(Ident::new("cfg", span)),
18                    delimiter: MacroDelimiter::Paren(token::Paren(span)),
19                    tokens: self.as_meta().into_token_stream(),
20                }),
21            })
22        }
23    }
24
25    pub(crate) fn as_meta(&self) -> impl ToTokens + '_ {
26        Print {
27            cfg: self,
28            span: Span::call_site(),
29        }
30    }
31}
32
33struct Print<'a, Cfg> {
34    cfg: &'a Cfg,
35    span: Span,
36}
37
38impl<'a> ToTokens for Print<'a, CfgExpr> {
39    fn to_tokens(&self, tokens: &mut TokenStream) {
40        let span = self.span;
41        let print = |cfg| Print { cfg, span };
42        match self.cfg {
43            CfgExpr::Unconditional => unreachable!(),
44            CfgExpr::Eq(ident, value) => {
45                ident.to_tokens(tokens);
46                if let Some(value) = value {
47                    Token![=](span).to_tokens(tokens);
48                    value.to_tokens(tokens);
49                }
50            }
51            CfgExpr::All(inner) => {
52                tokens.append(Ident::new("all", span));
53                let mut group = TokenStream::new();
54                group.append_separated(inner.iter().map(print), Token![,](span));
55                tokens.append(Group::new(Delimiter::Parenthesis, group));
56            }
57            CfgExpr::Any(inner) => {
58                tokens.append(Ident::new("any", span));
59                let mut group = TokenStream::new();
60                group.append_separated(inner.iter().map(print), Token![,](span));
61                tokens.append(Group::new(Delimiter::Parenthesis, group));
62            }
63            CfgExpr::Not(inner) => {
64                tokens.append(Ident::new("not", span));
65                let group = print(inner).into_token_stream();
66                tokens.append(Group::new(Delimiter::Parenthesis, group));
67            }
68        }
69    }
70}
71
72impl<'a> ToTokens for Print<'a, ComputedCfg<'a>> {
73    fn to_tokens(&self, tokens: &mut TokenStream) {
74        let span = self.span;
75        match *self.cfg {
76            ComputedCfg::Leaf(cfg) => Print { cfg, span }.to_tokens(tokens),
77            ComputedCfg::All(ref inner) => {
78                tokens.append(Ident::new("all", span));
79                let mut group = TokenStream::new();
80                group.append_separated(
81                    inner.iter().map(|&cfg| Print { cfg, span }),
82                    Token![,](span),
83                );
84                tokens.append(Group::new(Delimiter::Parenthesis, group));
85            }
86            ComputedCfg::Any(ref inner) => {
87                tokens.append(Ident::new("any", span));
88                let mut group = TokenStream::new();
89                group
90                    .append_separated(inner.iter().map(|cfg| Print { cfg, span }), Token![,](span));
91                tokens.append(Group::new(Delimiter::Parenthesis, group));
92            }
93        }
94    }
95}