1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
//! Implementation crate for `multiversion`.
extern crate proc_macro;

mod cfg;
mod dispatcher;
mod match_target;
mod multiversion;
mod target;
mod util;

use proc_macro2::TokenStream;
use quote::{quote, ToTokens};
use syn::{parse::Nothing, parse_macro_input, punctuated::Punctuated, ItemFn};

#[proc_macro_attribute]
pub fn multiversion(
    attr: proc_macro::TokenStream,
    input: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
    let func = parse_macro_input!(input as ItemFn);
    match multiversion::make_multiversioned_fn(attr.into(), func) {
        Ok(tokens) => tokens.into_token_stream(),
        Err(err) => err.to_compile_error(),
    }
    .into()
}

#[proc_macro_attribute]
pub fn target(
    attr: proc_macro::TokenStream,
    input: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
    let target = parse_macro_input!(attr as syn::LitStr);
    let func = parse_macro_input!(input as ItemFn);
    match target::make_target_fn(target, func) {
        Ok(tokens) => tokens.into_token_stream(),
        Err(err) => err.to_compile_error(),
    }
    .into()
}

#[proc_macro_attribute]
pub fn inherit_target(
    attr: proc_macro::TokenStream,
    input: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
    parse_macro_input!(attr as Nothing);
    let func = parse_macro_input!(input as ItemFn);
    quote! {
        __multiversion::inherit_target! { #func }
    }
    .into()
}

#[proc_macro]
pub fn selected_target(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    parse_macro_input!(input as Nothing);
    quote! {
        __multiversion::FEATURES
    }
    .into()
}

#[proc_macro_attribute]
pub fn target_cfg(
    attr: proc_macro::TokenStream,
    input: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
    let attr = TokenStream::from(attr);
    let input = TokenStream::from(input);
    quote! {
        __multiversion::target_cfg!{ [#attr] #input }
    }
    .into()
}

#[proc_macro_attribute]
pub fn target_cfg_attr(
    attr: proc_macro::TokenStream,
    input: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
    let attr = TokenStream::from(attr);
    let input = TokenStream::from(input);
    quote! {
        __multiversion::target_cfg_attr!{ [#attr] #input }
    }
    .into()
}

#[proc_macro]
pub fn target_cfg_f(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let input = TokenStream::from(input);
    quote! {
        __multiversion::target_cfg_f!{ #input }
    }
    .into()
}

#[proc_macro_attribute]
pub fn target_cfg_impl(
    attr: proc_macro::TokenStream,
    input: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
    let meta = parse_macro_input!(attr with Punctuated::parse_terminated);
    let input = TokenStream::from(input);

    let meta = cfg::transform(meta);
    quote! {
        #[cfg(#meta)]
        #input
    }
    .into()
}

#[proc_macro_attribute]
pub fn target_cfg_attr_impl(
    attr: proc_macro::TokenStream,
    input: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
    let mut meta = parse_macro_input!(attr with Punctuated::parse_terminated);
    let input = TokenStream::from(input);

    let attr = meta.pop().unwrap();
    let meta = cfg::transform(meta);
    quote! {
        #[cfg_attr(#meta, #attr)]
        #input
    }
    .into()
}

#[proc_macro]
pub fn target_cfg_f_impl(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let meta = parse_macro_input!(input with Punctuated::parse_terminated);

    let meta = cfg::transform(meta);
    quote! {
        cfg!(#meta)
    }
    .into()
}

#[proc_macro]
pub fn match_target(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let input = TokenStream::from(input);
    quote! {
        __multiversion::match_target!{ #input }
    }
    .into()
}

#[proc_macro]
pub fn match_target_impl(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let match_target = parse_macro_input!(input as match_target::MatchTarget);
    match_target.into_token_stream().into()
}