1use proc_macro2::{Ident, TokenStream};
2use syn::{Attribute, Meta};
3
4pub fn has_attribute(attrs: &Vec<Attribute>, attr_name: &str) -> Option<(Ident, Meta)> {
6 for attr in attrs {
7 if let Ok(meta) = attr.parse_meta() {
8 let path = meta.path();
9 if let Some(ident) = path.get_ident() {
10 if ident == attr_name {
11 return Some((ident.clone(), meta.clone()));
12 }
13 }
14 }
15 }
16
17 None
18}
19
20pub fn get_list_attr(
22 attrs: &Vec<Attribute>,
23 attr_name: &str,
24) -> Result<Vec<TokenStream>, TokenStream> {
25 let mut matches = vec![];
26
27 for attr in attrs {
28 let meta = attr.parse_meta().map_err(|err| err.to_compile_error())?;
29 if let syn::Meta::List(path) = meta {
30 if let Some(ident) = path.path.get_ident() {
31 if ident == attr_name {
32 let tokens = attr.parse_args().map_err(|err| err.to_compile_error())?;
33 matches.push(tokens);
34 }
35 }
36 }
37 }
38
39 Ok(matches)
40}
41
42pub fn validate_attributes(
45 attrs: &Vec<Attribute>,
46 base: Option<&str>,
47 other: &[(&str, bool)],
48 illegal: &[&str],
49) -> Result<(), TokenStream> {
50 for attr in illegal {
51 if let Some(ident) = has_attribute(attrs, attr) {
52 return Err(
53 syn::Error::new(ident.0.span(), "This attribute is not allowed here")
54 .to_compile_error()
55 .into(),
56 );
57 }
58 }
59
60 for attr in other {
61 let found = has_attribute(attrs, attr.0);
62 if let Some(found) = found {
63 if let Some(base) = base {
64 if !has_attribute(attrs, base).is_some() {
65 return Err(syn::Error::new(
66 found.0.span(),
67 format!("This attribute requires the #[{}] attribute", base),
68 )
69 .to_compile_error()
70 .into());
71 }
72 }
73
74 match found.1 {
75 Meta::Path(_) => {
76 if attr.1 {
77 return Err(syn::Error::new(
78 found.0.span(),
79 "This attribute is missing a parameter",
80 )
81 .to_compile_error()
82 .into());
83 }
84 }
85 Meta::List(_) => {
86 if !attr.1 {
87 return Err(
88 syn::Error::new(found.0.span(), "This attribute isn't a list")
89 .to_compile_error()
90 .into(),
91 );
92 }
93 }
94 _ => unimplemented!(),
95 };
96 }
97 }
98
99 Ok(())
100}