rustversion/
expand.rs

1use crate::attr::{self, Then};
2use crate::error::{Error, Result};
3use crate::{constfn, expr, iter, token};
4use proc_macro::{Delimiter, Group, Ident, Punct, Spacing, Span, TokenStream, TokenTree};
5use std::iter::FromIterator;
6
7pub fn cfg(introducer: &str, args: TokenStream, input: TokenStream) -> TokenStream {
8    try_cfg(introducer, args, input).unwrap_or_else(Error::into_compile_error)
9}
10
11fn try_cfg(introducer: &str, args: TokenStream, input: TokenStream) -> Result<TokenStream> {
12    let introducer = Ident::new(introducer, Span::call_site());
13
14    let mut full_args = TokenStream::from(TokenTree::Ident(introducer));
15    if !args.is_empty() {
16        full_args.extend(std::iter::once(TokenTree::Group(Group::new(
17            Delimiter::Parenthesis,
18            args,
19        ))));
20    }
21
22    let ref mut full_args = iter::new(full_args);
23    let expr = expr::parse(full_args)?;
24    token::parse_end(full_args)?;
25
26    if expr.eval(crate::RUSTVERSION) {
27        Ok(input)
28    } else {
29        Ok(TokenStream::new())
30    }
31}
32
33pub fn try_attr(args: attr::Args, input: TokenStream) -> Result<TokenStream> {
34    if !args.condition.eval(crate::RUSTVERSION) {
35        return Ok(input);
36    }
37
38    match args.then {
39        Then::Const(const_token) => constfn::insert_const(input, const_token),
40        Then::Attribute(then) => {
41            // #[cfg_attr(all(), #then)]
42            Ok(TokenStream::from_iter(
43                vec![
44                    TokenTree::Punct(Punct::new('#', Spacing::Alone)),
45                    TokenTree::Group(Group::new(
46                        Delimiter::Bracket,
47                        TokenStream::from_iter(vec![
48                            TokenTree::Ident(Ident::new("cfg_attr", Span::call_site())),
49                            TokenTree::Group(Group::new(
50                                Delimiter::Parenthesis,
51                                TokenStream::from_iter(
52                                    vec![
53                                        TokenTree::Ident(Ident::new("all", Span::call_site())),
54                                        TokenTree::Group(Group::new(
55                                            Delimiter::Parenthesis,
56                                            TokenStream::new(),
57                                        )),
58                                        TokenTree::Punct(Punct::new(',', Spacing::Alone)),
59                                    ]
60                                    .into_iter()
61                                    .chain(then),
62                                ),
63                            )),
64                        ]),
65                    )),
66                ]
67                .into_iter()
68                .chain(input),
69            ))
70        }
71    }
72}