blob: a502e3609417de258b8b2ccd6cbba2b3f5cb0942 (
plain) (
blame)
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
|
use crate::SynResult;
use crate::config::default_feature_name;
use proc_macro::TokenStream;
use quote::quote;
use syn::{
ItemFn, LitStr,
parse::{Parse, ParseStream},
parse_macro_input,
};
#[doc = include_str!("../doc/args/func.md")]
pub struct FuncArgs {
pub feature_name: String,
}
impl Default for FuncArgs {
fn default() -> Self {
FuncArgs {
feature_name: default_feature_name().to_string(),
}
}
}
impl Parse for FuncArgs {
fn parse(input: ParseStream) -> SynResult<Self> {
if input.is_empty() {
return Ok(FuncArgs::default());
}
// Parse: "feature_name"
let feat_lit: LitStr = input.parse()?;
let feature_name = feat_lit.value();
Ok(FuncArgs { feature_name })
}
}
pub(crate) fn func(attr: TokenStream, item: TokenStream) -> TokenStream {
let args = parse_macro_input!(attr as FuncArgs);
let feature_name = &args.feature_name;
let input_fn = parse_macro_input!(item as ItemFn);
let attrs = &input_fn.attrs;
let vis = &input_fn.vis;
let sig = &input_fn.sig;
let block = &input_fn.block;
let expanded = quote! {
#(#attrs)*
#[cfg(not(feature = #feature_name))]
#vis #sig #block
#(#attrs)*
#[cfg(feature = #feature_name)]
#vis async #sig #block
};
TokenStream::from(expanded)
}
/// Test module for `FuncArgs` parsing.
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn empty_input_defaults_to_async() {
// Input: empty → defaults to "foo_async"
let input = proc_macro2::TokenStream::new();
let args: FuncArgs = syn::parse2(input).unwrap();
assert_eq!(args.feature_name, "foo_async");
}
#[test]
fn custom_feature_name_parsed() {
// Input: "custom_name"
let input: proc_macro2::TokenStream = "\"custom_name\"".parse().unwrap();
let args: FuncArgs = syn::parse2(input).unwrap();
assert_eq!(args.feature_name, "custom_name");
}
#[test]
fn integer_literal_is_rejected() {
let input: proc_macro2::TokenStream = "42".parse().unwrap();
assert!(syn::parse2::<FuncArgs>(input).is_err());
}
#[test]
fn multiple_args_are_rejected() {
let input: proc_macro2::TokenStream = r#""a" "b""#.parse().unwrap();
assert!(syn::parse2::<FuncArgs>(input).is_err());
}
}
|