cfg_exclusive/
lib.rs

1extern crate proc_macro;
2
3use proc_macro::TokenStream;
4use quote::quote;
5use syn::{
6    parse::{Parse, ParseStream, Result},
7    parse_macro_input, Expr, ExprArray, ExprLit, Ident, Lit, LitStr, Token,
8};
9
10struct ExclusiveFeatures {
11    name: Ident,
12    features: Vec<String>,
13    msg: LitStr,
14}
15
16impl Parse for ExclusiveFeatures {
17    fn parse(input: ParseStream) -> Result<Self> {
18        let name: Ident = input.parse()?;
19        input.parse::<Token![,]>()?;
20        let features: ExprArray = input.parse()?;
21        input.parse::<Token![,]>()?;
22        let msg: LitStr = input.parse()?;
23        Ok(ExclusiveFeatures {
24            name,
25            features: features
26                .elems
27                .iter()
28                .map(|e| {
29                    if let Expr::Lit(ExprLit {
30                        lit: Lit::Str(s), ..
31                    }) = e
32                    {
33                        s.value()
34                    } else {
35                        panic!("Expected string literal")
36                    }
37                })
38                .collect(),
39            msg,
40        })
41    }
42}
43
44#[proc_macro]
45pub fn cfg_exclusive(input: TokenStream) -> TokenStream {
46    let ExclusiveFeatures {
47        name,
48        features,
49        msg,
50    } = parse_macro_input!(input);
51
52    let mut permutations = vec![];
53
54    for f in features.iter() {
55        let mut cfg_exprs = vec![];
56
57        for ef in features.iter().filter(|&x| x != f) {
58            cfg_exprs.push(quote! {feature = #ef});
59        }
60
61        permutations.push(quote! {all(feature = #f, any(#(#cfg_exprs),*))});
62    }
63
64    TokenStream::from(quote! {
65        fn #name() {
66            #[cfg(any(#(#permutations),*))]
67            compile_error!(#msg);
68        }
69    })
70}