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
use syn::{Expr, Ident, Lit, Meta, Token, punctuated::Punctuated};
use crate::panic;
/// Parse a framework option pair like `serde(Serialize, Deserialize)` or `rocket(FromFormField, FromParam)` into two boolean flags.
///
/// The `feature_enabled` argument should be the result of `cfg!(feature = ...)` for the corresponding framework feature.
pub(crate) fn meta_2_flags(
meta: &Meta,
feature_name: &str,
feature_enabled: bool,
first_name: &str,
second_name: &str,
) -> syn::Result<(bool, bool)> {
match meta {
Meta::Path(path) => {
if feature_enabled {
Ok((true, true))
} else {
Err(syn::Error::new_spanned(
path,
format!("the `{feature_name}` feature is not enabled"),
))
}
},
Meta::NameValue(name_value) => {
if let Expr::Lit(lit) = &name_value.value
&& let Lit::Bool(lit) = &lit.lit
{
let b = lit.value;
if b && !feature_enabled {
return Err(syn::Error::new_spanned(
lit,
format!(
"the `{feature_name}` feature is not enabled, so the value cannot be \
`true`"
),
));
}
return Ok((b, b));
}
Err(syn::Error::new_spanned(&name_value.value, "expected a bool"))
},
Meta::List(list) => {
let result =
list.parse_args_with(Punctuated::<Ident, Token![,]>::parse_separated_nonempty)?;
let mut first = false;
let mut second = false;
for p in result {
let name = p.to_string();
if name == first_name {
if first {
return Err(panic::parameter_reset(&p));
}
first = true;
} else if name == second_name {
if second {
return Err(panic::parameter_reset(&p));
}
second = true;
} else {
return Err(syn::Error::new_spanned(
&p,
format!("expected {first_name}/{second_name}"),
));
}
if !feature_enabled {
return Err(syn::Error::new_spanned(
&p,
format!(
"cannot implement `{p}` because the `{feature_name}` feature is not \
enabled"
),
));
}
}
Ok((first, second))
},
}
}