multiversion_macros/
lib.rs

1//! Implementation crate for `multiversion`.
2extern crate proc_macro;
3
4mod cfg;
5mod dispatcher;
6mod match_target;
7mod multiversion;
8mod target;
9mod util;
10
11use proc_macro2::TokenStream;
12use quote::{quote, ToTokens};
13use syn::{parse::Nothing, parse_macro_input, punctuated::Punctuated, ItemFn};
14
15#[proc_macro_attribute]
16pub fn multiversion(
17    attr: proc_macro::TokenStream,
18    input: proc_macro::TokenStream,
19) -> proc_macro::TokenStream {
20    let func = parse_macro_input!(input as ItemFn);
21    match multiversion::make_multiversioned_fn(attr.into(), func) {
22        Ok(tokens) => tokens.into_token_stream(),
23        Err(err) => err.to_compile_error(),
24    }
25    .into()
26}
27
28#[proc_macro_attribute]
29pub fn target(
30    attr: proc_macro::TokenStream,
31    input: proc_macro::TokenStream,
32) -> proc_macro::TokenStream {
33    let target = parse_macro_input!(attr as syn::LitStr);
34    let func = parse_macro_input!(input as ItemFn);
35    match target::make_target_fn(target, func) {
36        Ok(tokens) => tokens.into_token_stream(),
37        Err(err) => err.to_compile_error(),
38    }
39    .into()
40}
41
42#[proc_macro_attribute]
43pub fn inherit_target(
44    attr: proc_macro::TokenStream,
45    input: proc_macro::TokenStream,
46) -> proc_macro::TokenStream {
47    parse_macro_input!(attr as Nothing);
48    let func = parse_macro_input!(input as ItemFn);
49    quote! {
50        __multiversion::inherit_target! { #func }
51    }
52    .into()
53}
54
55#[proc_macro]
56pub fn selected_target(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
57    parse_macro_input!(input as Nothing);
58    quote! {
59        __multiversion::FEATURES
60    }
61    .into()
62}
63
64#[proc_macro_attribute]
65pub fn target_cfg(
66    attr: proc_macro::TokenStream,
67    input: proc_macro::TokenStream,
68) -> proc_macro::TokenStream {
69    let attr = TokenStream::from(attr);
70    let input = TokenStream::from(input);
71    quote! {
72        __multiversion::target_cfg!{ [#attr] #input }
73    }
74    .into()
75}
76
77#[proc_macro_attribute]
78pub fn target_cfg_attr(
79    attr: proc_macro::TokenStream,
80    input: proc_macro::TokenStream,
81) -> proc_macro::TokenStream {
82    let attr = TokenStream::from(attr);
83    let input = TokenStream::from(input);
84    quote! {
85        __multiversion::target_cfg_attr!{ [#attr] #input }
86    }
87    .into()
88}
89
90#[proc_macro]
91pub fn target_cfg_f(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
92    let input = TokenStream::from(input);
93    quote! {
94        __multiversion::target_cfg_f!{ #input }
95    }
96    .into()
97}
98
99#[proc_macro_attribute]
100pub fn target_cfg_impl(
101    attr: proc_macro::TokenStream,
102    input: proc_macro::TokenStream,
103) -> proc_macro::TokenStream {
104    let meta = parse_macro_input!(attr with Punctuated::parse_terminated);
105    let input = TokenStream::from(input);
106
107    match cfg::transform(meta) {
108        Ok(meta) => {
109            quote! {
110                #[cfg(#meta)]
111                #input
112            }
113        }
114        Err(err) => err.to_compile_error(),
115    }
116    .into()
117}
118
119#[proc_macro_attribute]
120pub fn target_cfg_attr_impl(
121    attr: proc_macro::TokenStream,
122    input: proc_macro::TokenStream,
123) -> proc_macro::TokenStream {
124    let mut meta = parse_macro_input!(attr with Punctuated::parse_terminated);
125    let input = TokenStream::from(input);
126
127    let attr = meta.pop().unwrap();
128    match cfg::transform(meta) {
129        Ok(meta) => {
130            quote! {
131                #[cfg_attr(#meta, #attr)]
132                #input
133            }
134        }
135        Err(err) => err.to_compile_error(),
136    }
137    .into()
138}
139
140#[proc_macro]
141pub fn target_cfg_f_impl(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
142    let meta = parse_macro_input!(input with Punctuated::parse_terminated);
143
144    match cfg::transform(meta) {
145        Ok(meta) => {
146            quote! {
147                cfg!(#meta)
148            }
149        }
150        Err(err) => err.to_compile_error(),
151    }
152    .into()
153}
154
155#[proc_macro]
156pub fn match_target(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
157    let input = TokenStream::from(input);
158    quote! {
159        __multiversion::match_target!{ #input }
160    }
161    .into()
162}
163
164#[proc_macro]
165pub fn match_target_impl(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
166    let match_target = parse_macro_input!(input as match_target::MatchTarget);
167    match_target.into_token_stream().into()
168}